Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


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

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

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_posting.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 83.82 KiB


0001  <?php
0002  /**
0003  *
0004  * This file is part of the phpBB Forum Software package.
0005  *
0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007  * @license GNU General Public License, version 2 (GPL-2.0)
0008  *
0009  * For full copyright and license information, please see
0010  * the docs/CREDITS.txt file.
0011  *
0012  */
0013   
0014  /**
0015  * @ignore
0016  */
0017  if (!defined('IN_PHPBB'))
0018  {
0019      exit;
0020  }
0021   
0022  /**
0023  * Fill smiley templates (or just the variables) with smilies, either in a window or inline
0024  */
0025  function generate_smilies($mode, $forum_id)
0026  {
0027      global $db, $user, $config, $template, $phpbb_dispatcher, $request;
0028      global $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_path_helper;
0029   
0030      /* @var $pagination \phpbb\pagination */
0031      $pagination = $phpbb_container->get('pagination');
0032      $base_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&amp;f=' . $forum_id);
0033      $start = $request->variable('start', 0);
0034   
0035      if ($mode == 'window')
0036      {
0037          if ($forum_id)
0038          {
0039              $sql = 'SELECT forum_style
0040                  FROM ' . FORUMS_TABLE . "
0041                  WHERE forum_id = $forum_id";
0042              $result = $db->sql_query_limit($sql, 1);
0043              $row = $db->sql_fetchrow($result);
0044              $db->sql_freeresult($result);
0045   
0046              $user->setup('posting', (int) $row['forum_style']);
0047          }
0048          else
0049          {
0050              $user->setup('posting');
0051          }
0052   
0053          page_header($user->lang['SMILIES']);
0054   
0055          $sql = 'SELECT COUNT(smiley_id) AS item_count
0056              FROM ' . SMILIES_TABLE . '
0057              GROUP BY smiley_url';
0058          $result = $db->sql_query($sql, 3600);
0059   
0060          $smiley_count = 0;
0061          while ($row = $db->sql_fetchrow($result))
0062          {
0063              ++$smiley_count;
0064          }
0065          $db->sql_freeresult($result);
0066   
0067          $template->set_filenames(array(
0068              'body' => 'posting_smilies.html')
0069          );
0070   
0071          $start = $pagination->validate_start($start, $config['smilies_per_page'], $smiley_count);
0072          $pagination->generate_template_pagination($base_url, 'pagination', 'start', $smiley_count, $config['smilies_per_page'], $start);
0073      }
0074   
0075      $display_link = false;
0076      if ($mode == 'inline')
0077      {
0078          $sql = 'SELECT smiley_id
0079              FROM ' . SMILIES_TABLE . '
0080              WHERE display_on_posting = 0';
0081          $result = $db->sql_query_limit($sql, 1, 0, 3600);
0082   
0083          if ($row = $db->sql_fetchrow($result))
0084          {
0085              $display_link = true;
0086          }
0087          $db->sql_freeresult($result);
0088      }
0089   
0090      if ($mode == 'window')
0091      {
0092          $sql = 'SELECT smiley_url, MIN(emotion) as emotion, MIN(code) AS code, smiley_width, smiley_height, MIN(smiley_order) AS min_smiley_order
0093              FROM ' . SMILIES_TABLE . '
0094              GROUP BY smiley_url, smiley_width, smiley_height
0095              ORDER BY min_smiley_order';
0096          $result = $db->sql_query_limit($sql, $config['smilies_per_page'], $start, 3600);
0097      }
0098      else
0099      {
0100          $sql = 'SELECT *
0101              FROM ' . SMILIES_TABLE . '
0102              WHERE display_on_posting = 1
0103              ORDER BY smiley_order';
0104          $result = $db->sql_query($sql, 3600);
0105      }
0106   
0107      $smilies = array();
0108      while ($row = $db->sql_fetchrow($result))
0109      {
0110          if (empty($smilies[$row['smiley_url']]))
0111          {
0112              $smilies[$row['smiley_url']] = $row;
0113          }
0114      }
0115      $db->sql_freeresult($result);
0116   
0117      if (sizeof($smilies))
0118      {
0119          $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_path_helper->get_web_root_path();
0120   
0121          foreach ($smilies as $row)
0122          {
0123              /**
0124              * Modify smiley root path before populating smiley list
0125              *
0126              * @event core.generate_smilies_before
0127              * @var string  root_path root_path for smilies
0128              * @since 3.1.11-RC1
0129              */
0130              $vars = array('root_path');
0131              extract($phpbb_dispatcher->trigger_event('core.generate_smilies_before', compact($vars)));
0132              $template->assign_block_vars('smiley', array(
0133                  'SMILEY_CODE'    => $row['code'],
0134                  'A_SMILEY_CODE'    => addslashes($row['code']),
0135                  'SMILEY_IMG'    => $root_path . $config['smilies_path'] . '/' . $row['smiley_url'],
0136                  'SMILEY_WIDTH'    => $row['smiley_width'],
0137                  'SMILEY_HEIGHT'    => $row['smiley_height'],
0138                  'SMILEY_DESC'    => $row['emotion'])
0139              );
0140          }
0141      }
0142   
0143      /**
0144      * This event is called after the smilies are populated
0145      *
0146      * @event core.generate_smilies_after
0147      * @var    string    mode            Mode of the smilies: window|inline
0148      * @var    int        forum_id        The forum ID we are currently in
0149      * @var    bool    display_link    Shall we display the "more smilies" link?
0150      * @since 3.1.0-a1
0151      */
0152      $vars = array('mode', 'forum_id', 'display_link');
0153      extract($phpbb_dispatcher->trigger_event('core.generate_smilies_after', compact($vars)));
0154   
0155      if ($mode == 'inline' && $display_link)
0156      {
0157          $template->assign_vars(array(
0158              'S_SHOW_SMILEY_LINK'     => true,
0159              'U_MORE_SMILIES'         => $base_url,
0160          ));
0161      }
0162   
0163      if ($mode == 'window')
0164      {
0165          page_footer();
0166      }
0167  }
0168   
0169  /**
0170  * Update last post information
0171  * Should be used instead of sync() if only the last post information are out of sync... faster
0172  *
0173  * @param    string    $type                Can be forum|topic
0174  * @param    mixed    $ids                topic/forum ids
0175  * @param    bool    $return_update_sql    true: SQL query shall be returned, false: execute SQL
0176  */
0177  function update_post_information($type, $ids, $return_update_sql = false)
0178  {
0179      global $db;
0180   
0181      if (empty($ids))
0182      {
0183          return;
0184      }
0185      if (!is_array($ids))
0186      {
0187          $ids = array($ids);
0188      }
0189   
0190      $update_sql = $empty_forums = $not_empty_forums = array();
0191   
0192      if ($type != 'topic')
0193      {
0194          $topic_join = ', ' . TOPICS_TABLE . ' t';
0195          $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_visibility = ' . ITEM_APPROVED;
0196      }
0197      else
0198      {
0199          $topic_join = '';
0200          $topic_condition = '';
0201      }
0202   
0203      if (sizeof($ids) == 1)
0204      {
0205          $sql = 'SELECT MAX(p.post_id) as last_post_id
0206              FROM ' . POSTS_TABLE . " p $topic_join
0207              WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
0208                  $topic_condition
0209                  AND p.post_visibility = " . ITEM_APPROVED;
0210      }
0211      else
0212      {
0213          $sql = 'SELECT p.' . $type . '_id, MAX(p.post_id) as last_post_id
0214              FROM ' . POSTS_TABLE . " p $topic_join
0215              WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
0216                  $topic_condition
0217                  AND p.post_visibility = " . ITEM_APPROVED . "
0218              GROUP BY p.{$type}_id";
0219      }
0220      $result = $db->sql_query($sql);
0221   
0222      $last_post_ids = array();
0223      while ($row = $db->sql_fetchrow($result))
0224      {
0225          if (sizeof($ids) == 1)
0226          {
0227              $row[$type . '_id'] = $ids[0];
0228          }
0229   
0230          if ($type == 'forum')
0231          {
0232              $not_empty_forums[] = $row['forum_id'];
0233   
0234              if (empty($row['last_post_id']))
0235              {
0236                  $empty_forums[] = $row['forum_id'];
0237              }
0238          }
0239   
0240          $last_post_ids[] = $row['last_post_id'];
0241      }
0242      $db->sql_freeresult($result);
0243   
0244      if ($type == 'forum')
0245      {
0246          $empty_forums = array_merge($empty_forums, array_diff($ids, $not_empty_forums));
0247   
0248          foreach ($empty_forums as $void => $forum_id)
0249          {
0250              $update_sql[$forum_id][] = 'forum_last_post_id = 0';
0251              $update_sql[$forum_id][] = "forum_last_post_subject = ''";
0252              $update_sql[$forum_id][] = 'forum_last_post_time = 0';
0253              $update_sql[$forum_id][] = 'forum_last_poster_id = 0';
0254              $update_sql[$forum_id][] = "forum_last_poster_name = ''";
0255              $update_sql[$forum_id][] = "forum_last_poster_colour = ''";
0256          }
0257      }
0258   
0259      if (sizeof($last_post_ids))
0260      {
0261          $sql = 'SELECT p.' . $type . '_id, p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour
0262              FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
0263              WHERE p.poster_id = u.user_id
0264                  AND ' . $db->sql_in_set('p.post_id', $last_post_ids);
0265          $result = $db->sql_query($sql);
0266   
0267          while ($row = $db->sql_fetchrow($result))
0268          {
0269              $update_sql[$row["{$type}_id"]][] = $type . '_last_post_id = ' . (int) $row['post_id'];
0270              $update_sql[$row["{$type}_id"]][] = "{$type}_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'";
0271              $update_sql[$row["{$type}_id"]][] = $type . '_last_post_time = ' . (int) $row['post_time'];
0272              $update_sql[$row["{$type}_id"]][] = $type . '_last_poster_id = ' . (int) $row['poster_id'];
0273              $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'";
0274              $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'";
0275          }
0276          $db->sql_freeresult($result);
0277      }
0278      unset($empty_forums, $ids, $last_post_ids);
0279   
0280      if ($return_update_sql || !sizeof($update_sql))
0281      {
0282          return $update_sql;
0283      }
0284   
0285      $table = ($type == 'forum') ? FORUMS_TABLE : TOPICS_TABLE;
0286   
0287      foreach ($update_sql as $update_id => $update_sql_ary)
0288      {
0289          $sql = "UPDATE $table
0290              SET " . implode(', ', $update_sql_ary) . "
0291              WHERE {$type}_id = $update_id";
0292          $db->sql_query($sql);
0293      }
0294   
0295      return;
0296  }
0297   
0298  /**
0299  * Generate Topic Icons for display
0300  */
0301  function posting_gen_topic_icons($mode, $icon_id)
0302  {
0303      global $phpbb_root_path, $config, $template, $cache;
0304   
0305      // Grab icons
0306      $icons = $cache->obtain_icons();
0307   
0308      if (!$icon_id)
0309      {
0310          $template->assign_var('S_NO_ICON_CHECKED', ' checked="checked"');
0311      }
0312   
0313      if (sizeof($icons))
0314      {
0315          $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path;
0316   
0317          foreach ($icons as $id => $data)
0318          {
0319              if ($data['display'])
0320              {
0321                  $template->assign_block_vars('topic_icon', array(
0322                      'ICON_ID'        => $id,
0323                      'ICON_IMG'        => $root_path . $config['icons_path'] . '/' . $data['img'],
0324                      'ICON_WIDTH'    => $data['width'],
0325                      'ICON_HEIGHT'    => $data['height'],
0326                      'ICON_ALT'        => $data['alt'],
0327   
0328                      'S_CHECKED'            => ($id == $icon_id) ? true : false,
0329                      'S_ICON_CHECKED'    => ($id == $icon_id) ? ' checked="checked"' : '')
0330                  );
0331              }
0332          }
0333   
0334          return true;
0335      }
0336   
0337      return false;
0338  }
0339   
0340  /**
0341  * Build topic types able to be selected
0342  */
0343  function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL)
0344  {
0345      global $auth, $user, $template;
0346   
0347      $toggle = false;
0348   
0349      $topic_types = array(
0350          'sticky'            => array('const' => POST_STICKY, 'lang' => 'POST_STICKY'),
0351          'announce'            => array('const' => POST_ANNOUNCE, 'lang' => 'POST_ANNOUNCEMENT'),
0352          'announce_global'    => array('const' => POST_GLOBAL, 'lang' => 'POST_GLOBAL')
0353      );
0354   
0355      $topic_type_array = array();
0356   
0357      foreach ($topic_types as $auth_key => $topic_value)
0358      {
0359          if ($auth->acl_get('f_' . $auth_key, $forum_id))
0360          {
0361              $toggle = true;
0362   
0363              $topic_type_array[] = array(
0364                  'VALUE'            => $topic_value['const'],
0365                  'S_CHECKED'        => ($cur_topic_type == $topic_value['const']) ? ' checked="checked"' : '',
0366                  'L_TOPIC_TYPE'    => $user->lang[$topic_value['lang']]
0367              );
0368          }
0369      }
0370   
0371      if ($toggle)
0372      {
0373          $topic_type_array = array_merge(array(0 => array(
0374              'VALUE'            => POST_NORMAL,
0375              'S_CHECKED'        => ($cur_topic_type == POST_NORMAL) ? ' checked="checked"' : '',
0376              'L_TOPIC_TYPE'    => $user->lang['POST_NORMAL'])),
0377   
0378              $topic_type_array
0379          );
0380   
0381          foreach ($topic_type_array as $array)
0382          {
0383              $template->assign_block_vars('topic_type', $array);
0384          }
0385   
0386          $template->assign_vars(array(
0387              'S_TOPIC_TYPE_STICKY'    => ($auth->acl_get('f_sticky', $forum_id)),
0388              'S_TOPIC_TYPE_ANNOUNCE'    => ($auth->acl_gets('f_announce', 'f_announce_global', $forum_id)),
0389          ));
0390      }
0391   
0392      return $toggle;
0393  }
0394   
0395  //
0396  // Attachment related functions
0397  //
0398   
0399  /**
0400  * Upload Attachment - filedata is generated here
0401  * Uses upload class
0402  *
0403  * @deprecated 3.2.0-a1 (To be removed: 3.4.0)
0404  *
0405  * @param string            $form_name        The form name of the file upload input
0406  * @param int            $forum_id        The id of the forum
0407  * @param bool            $local            Whether the file is local or not
0408  * @param string            $local_storage    The path to the local file
0409  * @param bool            $is_message        Whether it is a PM or not
0410  * @param array            $local_filedata    A filespec object created for the local file
0411  *
0412  * @return array File data array
0413  */
0414  function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false)
0415  {
0416      global $phpbb_container;
0417   
0418      /** @var \phpbb\attachment\manager $attachment_manager */
0419      $attachment_manager = $phpbb_container->get('attachment.manager');
0420      $file = $attachment_manager->upload($form_name, $forum_id, $local, $local_storage, $is_message, $local_filedata);
0421      unset($attachment_manager);
0422   
0423      return $file;
0424  }
0425   
0426  /**
0427  * Calculate the needed size for Thumbnail
0428  */
0429  function get_img_size_format($width, $height)
0430  {
0431      global $config;
0432   
0433      // Maximum Width the Image can take
0434      $max_width = ($config['img_max_thumb_width']) ? $config['img_max_thumb_width'] : 400;
0435   
0436      if ($width > $height)
0437      {
0438          return array(
0439              round($width * ($max_width / $width)),
0440              round($height * ($max_width / $width))
0441          );
0442      }
0443      else
0444      {
0445          return array(
0446              round($width * ($max_width / $height)),
0447              round($height * ($max_width / $height))
0448          );
0449      }
0450  }
0451   
0452  /**
0453  * Return supported image types
0454  */
0455  function get_supported_image_types($type = false)
0456  {
0457      if (@extension_loaded('gd'))
0458      {
0459          $format = imagetypes();
0460          $new_type = 0;
0461   
0462          if ($type !== false)
0463          {
0464              // Type is one of the IMAGETYPE constants - it is fetched from getimagesize()
0465              switch ($type)
0466              {
0467                  // GIF
0468                  case IMAGETYPE_GIF:
0469                      $new_type = ($format & IMG_GIF) ? IMG_GIF : false;
0470                  break;
0471   
0472                  // JPG, JPC, JP2
0473                  case IMAGETYPE_JPEG:
0474                  case IMAGETYPE_JPC:
0475                  case IMAGETYPE_JPEG2000:
0476                  case IMAGETYPE_JP2:
0477                  case IMAGETYPE_JPX:
0478                  case IMAGETYPE_JB2:
0479                      $new_type = ($format & IMG_JPG) ? IMG_JPG : false;
0480                  break;
0481   
0482                  // PNG
0483                  case IMAGETYPE_PNG:
0484                      $new_type = ($format & IMG_PNG) ? IMG_PNG : false;
0485                  break;
0486   
0487                  // WBMP
0488                  case IMAGETYPE_WBMP:
0489                      $new_type = ($format & IMG_WBMP) ? IMG_WBMP : false;
0490                  break;
0491              }
0492          }
0493          else
0494          {
0495              $new_type = array();
0496              $go_through_types = array(IMG_GIF, IMG_JPG, IMG_PNG, IMG_WBMP);
0497   
0498              foreach ($go_through_types as $check_type)
0499              {
0500                  if ($format & $check_type)
0501                  {
0502                      $new_type[] = $check_type;
0503                  }
0504              }
0505          }
0506   
0507          return array(
0508              'gd'        => ($new_type) ? true : false,
0509              'format'    => $new_type,
0510              'version'    => (function_exists('imagecreatetruecolor')) ? 2 : 1
0511          );
0512      }
0513   
0514      return array('gd' => false);
0515  }
0516   
0517  /**
0518  * Create Thumbnail
0519  */
0520  function create_thumbnail($source, $destination, $mimetype)
0521  {
0522      global $config, $phpbb_filesystem;
0523   
0524      $min_filesize = (int) $config['img_min_thumb_filesize'];
0525      $img_filesize = (file_exists($source)) ? @filesize($source) : false;
0526   
0527      if (!$img_filesize || $img_filesize <= $min_filesize)
0528      {
0529          return false;
0530      }
0531   
0532      $dimension = @getimagesize($source);
0533   
0534      if ($dimension === false)
0535      {
0536          return false;
0537      }
0538   
0539      list($width, $height, $type, ) = $dimension;
0540   
0541      if (empty($width) || empty($height))
0542      {
0543          return false;
0544      }
0545   
0546      list($new_width, $new_height) = get_img_size_format($width, $height);
0547   
0548      // Do not create a thumbnail if the resulting width/height is bigger than the original one
0549      if ($new_width >= $width && $new_height >= $height)
0550      {
0551          return false;
0552      }
0553   
0554      $used_imagick = false;
0555   
0556      // Only use ImageMagick if defined and the passthru function not disabled
0557      if ($config['img_imagick'] && function_exists('passthru'))
0558      {
0559          if (substr($config['img_imagick'], -1) !== '/')
0560          {
0561              $config['img_imagick'] .= '/';
0562          }
0563   
0564          @passthru(escapeshellcmd($config['img_imagick']) . 'convert' . ((defined('PHP_OS') && preg_match('#^win#i', PHP_OS)) ? '.exe' : '') . ' -quality 85 -geometry ' . $new_width . 'x' . $new_height . ' "' . str_replace('\\', '/', $source) . '" "' . str_replace('\\', '/', $destination) . '"');
0565   
0566          if (file_exists($destination))
0567          {
0568              $used_imagick = true;
0569          }
0570      }
0571   
0572      if (!$used_imagick)
0573      {
0574          $type = get_supported_image_types($type);
0575   
0576          if ($type['gd'])
0577          {
0578              // If the type is not supported, we are not able to create a thumbnail
0579              if ($type['format'] === false)
0580              {
0581                  return false;
0582              }
0583   
0584              switch ($type['format'])
0585              {
0586                  case IMG_GIF:
0587                      $image = @imagecreatefromgif($source);
0588                  break;
0589   
0590                  case IMG_JPG:
0591                      @ini_set('gd.jpeg_ignore_warning', 1);
0592                      $image = @imagecreatefromjpeg($source);
0593                  break;
0594   
0595                  case IMG_PNG:
0596                      $image = @imagecreatefrompng($source);
0597                  break;
0598   
0599                  case IMG_WBMP:
0600                      $image = @imagecreatefromwbmp($source);
0601                  break;
0602              }
0603   
0604              if (empty($image))
0605              {
0606                  return false;
0607              }
0608   
0609              if ($type['version'] == 1)
0610              {
0611                  $new_image = imagecreate($new_width, $new_height);
0612   
0613                  if ($new_image === false)
0614                  {
0615                      return false;
0616                  }
0617   
0618                  imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
0619              }
0620              else
0621              {
0622                  $new_image = imagecreatetruecolor($new_width, $new_height);
0623   
0624                  if ($new_image === false)
0625                  {
0626                      return false;
0627                  }
0628   
0629                  // Preserve alpha transparency (png for example)
0630                  @imagealphablending($new_image, false);
0631                  @imagesavealpha($new_image, true);
0632   
0633                  imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
0634              }
0635   
0636              // If we are in safe mode create the destination file prior to using the gd functions to circumvent a PHP bug
0637              if (@ini_get('safe_mode') || @strtolower(ini_get('safe_mode')) == 'on')
0638              {
0639                  @touch($destination);
0640              }
0641   
0642              switch ($type['format'])
0643              {
0644                  case IMG_GIF:
0645                      imagegif($new_image, $destination);
0646                  break;
0647   
0648                  case IMG_JPG:
0649                      imagejpeg($new_image, $destination, 90);
0650                  break;
0651   
0652                  case IMG_PNG:
0653                      imagepng($new_image, $destination);
0654                  break;
0655   
0656                  case IMG_WBMP:
0657                      imagewbmp($new_image, $destination);
0658                  break;
0659              }
0660   
0661              imagedestroy($new_image);
0662          }
0663          else
0664          {
0665              return false;
0666          }
0667      }
0668   
0669      if (!file_exists($destination))
0670      {
0671          return false;
0672      }
0673   
0674      try
0675      {
0676          $phpbb_filesystem->phpbb_chmod($destination, CHMOD_READ | CHMOD_WRITE);
0677      }
0678      catch (\phpbb\filesystem\exception\filesystem_exception $e)
0679      {
0680          // Do nothing
0681      }
0682   
0683      return true;
0684  }
0685   
0686  /**
0687  * Assign Inline attachments (build option fields)
0688  */
0689  function posting_gen_inline_attachments(&$attachment_data)
0690  {
0691      global $template;
0692   
0693      if (sizeof($attachment_data))
0694      {
0695          $s_inline_attachment_options = '';
0696   
0697          foreach ($attachment_data as $i => $attachment)
0698          {
0699              $s_inline_attachment_options .= '<option value="' . $i . '">' . utf8_basename($attachment['real_filename']) . '</option>';
0700          }
0701   
0702          $template->assign_var('S_INLINE_ATTACHMENT_OPTIONS', $s_inline_attachment_options);
0703   
0704          return true;
0705      }
0706   
0707      return false;
0708  }
0709   
0710  /**
0711  * Generate inline attachment entry
0712  */
0713  function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_attach_box = true)
0714  {
0715      global $template, $config, $phpbb_root_path, $phpEx, $user;
0716   
0717      // Some default template variables
0718      $template->assign_vars(array(
0719          'S_SHOW_ATTACH_BOX'    => $show_attach_box,
0720          'S_HAS_ATTACHMENTS'    => sizeof($attachment_data),
0721          'FILESIZE'            => $config['max_filesize'],
0722          'FILE_COMMENT'        => (isset($filename_data['filecomment'])) ? $filename_data['filecomment'] : '',
0723      ));
0724   
0725      if (sizeof($attachment_data))
0726      {
0727          // We display the posted attachments within the desired order.
0728          ($config['display_order']) ? krsort($attachment_data) : ksort($attachment_data);
0729   
0730          foreach ($attachment_data as $count => $attach_row)
0731          {
0732              $hidden = '';
0733              $attach_row['real_filename'] = utf8_basename($attach_row['real_filename']);
0734   
0735              foreach ($attach_row as $key => $value)
0736              {
0737                  $hidden .= '<input type="hidden" name="attachment_data[' . $count . '][' . $key . ']" value="' . $value . '" />';
0738              }
0739   
0740              $download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'mode=view&amp;id=' . (int) $attach_row['attach_id'], true, ($attach_row['is_orphan']) ? $user->session_id : false);
0741   
0742              $template->assign_block_vars('attach_row', array(
0743                  'FILENAME'            => utf8_basename($attach_row['real_filename']),
0744                  'A_FILENAME'        => addslashes(utf8_basename($attach_row['real_filename'])),
0745                  'FILE_COMMENT'        => $attach_row['attach_comment'],
0746                  'ATTACH_ID'            => $attach_row['attach_id'],
0747                  'S_IS_ORPHAN'        => $attach_row['is_orphan'],
0748                  'ASSOC_INDEX'        => $count,
0749                  'FILESIZE'            => get_formatted_filesize($attach_row['filesize']),
0750   
0751                  'U_VIEW_ATTACHMENT'    => $download_link,
0752                  'S_HIDDEN'            => $hidden)
0753              );
0754          }
0755      }
0756   
0757      return sizeof($attachment_data);
0758  }
0759   
0760  //
0761  // General Post functions
0762  //
0763   
0764  /**
0765  * Load Drafts
0766  */
0767  function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $msg_id = 0)
0768  {
0769      global $user, $db, $template, $auth;
0770      global $phpbb_root_path, $phpbb_dispatcher, $phpEx;
0771   
0772      $topic_ids = $forum_ids = $draft_rows = array();
0773   
0774      // Load those drafts not connected to forums/topics
0775      // If forum_id == 0 AND topic_id == 0 then this is a PM draft
0776      if (!$topic_id && !$forum_id)
0777      {
0778          $sql_and = ' AND d.forum_id = 0 AND d.topic_id = 0';
0779      }
0780      else
0781      {
0782          $sql_and = '';
0783          $sql_and .= ($forum_id) ? ' AND d.forum_id = ' . (int) $forum_id : '';
0784          $sql_and .= ($topic_id) ? ' AND d.topic_id = ' . (int) $topic_id : '';
0785      }
0786   
0787      $sql = 'SELECT d.*, f.forum_id, f.forum_name
0788          FROM ' . DRAFTS_TABLE . ' d
0789          LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = d.forum_id)
0790              WHERE d.user_id = ' . $user->data['user_id'] . "
0791              $sql_and
0792          ORDER BY d.save_time DESC";
0793      $result = $db->sql_query($sql);
0794   
0795      while ($row = $db->sql_fetchrow($result))
0796      {
0797          if ($row['topic_id'])
0798          {
0799              $topic_ids[] = (int) $row['topic_id'];
0800          }
0801          $draft_rows[] = $row;
0802      }
0803      $db->sql_freeresult($result);
0804   
0805      if (!sizeof($draft_rows))
0806      {
0807          return;
0808      }
0809   
0810      $topic_rows = array();
0811      if (sizeof($topic_ids))
0812      {
0813          $sql = 'SELECT topic_id, forum_id, topic_title, topic_poster
0814              FROM ' . TOPICS_TABLE . '
0815              WHERE ' . $db->sql_in_set('topic_id', array_unique($topic_ids));
0816          $result = $db->sql_query($sql);
0817   
0818          while ($row = $db->sql_fetchrow($result))
0819          {
0820              $topic_rows[$row['topic_id']] = $row;
0821          }
0822          $db->sql_freeresult($result);
0823      }
0824   
0825      /**
0826      * Drafts found and their topics
0827      * Edit $draft_rows in order to add or remove drafts loaded
0828      *
0829      * @event core.load_drafts_draft_list_result
0830      * @var    array    draft_rows            The drafts query result. Includes its forum id and everything about the draft
0831      * @var    array    topic_ids            The list of topics got from the topics table
0832      * @var    array    topic_rows            The topics that draft_rows references
0833      * @since 3.1.0-RC3
0834      */
0835      $vars = array('draft_rows', 'topic_ids', 'topic_rows');
0836      extract($phpbb_dispatcher->trigger_event('core.load_drafts_draft_list_result', compact($vars)));
0837   
0838      unset($topic_ids);
0839   
0840      $template->assign_var('S_SHOW_DRAFTS', true);
0841   
0842      foreach ($draft_rows as $draft)
0843      {
0844          $link_topic = $link_forum = $link_pm = false;
0845          $view_url = $title = '';
0846   
0847          if (isset($topic_rows[$draft['topic_id']])
0848              && (
0849                  ($topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_get('f_read', $topic_rows[$draft['topic_id']]['forum_id']))
0850                  ||
0851                  (!$topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_getf_global('f_read'))
0852              ))
0853          {
0854              $topic_forum_id = ($topic_rows[$draft['topic_id']]['forum_id']) ? $topic_rows[$draft['topic_id']]['forum_id'] : $forum_id;
0855   
0856              $link_topic = true;
0857              $view_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $topic_forum_id . '&amp;t=' . $draft['topic_id']);
0858              $title = $topic_rows[$draft['topic_id']]['topic_title'];
0859   
0860              $insert_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'f=' . $topic_forum_id . '&amp;t=' . $draft['topic_id'] . '&amp;mode=reply&amp;d=' . $draft['draft_id']);
0861          }
0862          else if ($draft['forum_id'] && $auth->acl_get('f_read', $draft['forum_id']))
0863          {
0864              $link_forum = true;
0865              $view_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $draft['forum_id']);
0866              $title = $draft['forum_name'];
0867   
0868              $insert_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'f=' . $draft['forum_id'] . '&amp;mode=post&amp;d=' . $draft['draft_id']);
0869          }
0870          else
0871          {
0872              // Either display as PM draft if forum_id and topic_id are empty or if access to the forums has been denied afterwards...
0873              $link_pm = true;
0874              $insert_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&amp;mode=compose&amp;d={$draft['draft_id']}" . (($pm_action) ? "&amp;action=$pm_action" : '') . (($msg_id) ? "&amp;p=$msg_id" : ''));
0875          }
0876   
0877          $template->assign_block_vars('draftrow', array(
0878              'DRAFT_ID'        => $draft['draft_id'],
0879              'DATE'            => $user->format_date($draft['save_time']),
0880              'DRAFT_SUBJECT'    => $draft['draft_subject'],
0881   
0882              'TITLE'            => $title,
0883              'U_VIEW'        => $view_url,
0884              'U_INSERT'        => $insert_url,
0885   
0886              'S_LINK_PM'        => $link_pm,
0887              'S_LINK_TOPIC'    => $link_topic,
0888              'S_LINK_FORUM'    => $link_forum)
0889          );
0890      }
0891  }
0892   
0893  /**
0894  * Topic Review
0895  */
0896  function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id = 0, $show_quote_button = true)
0897  {
0898      global $user, $auth, $db, $template;
0899      global $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
0900   
0901      /* @var $phpbb_content_visibility \phpbb\content_visibility */
0902      $phpbb_content_visibility = $phpbb_container->get('content.visibility');
0903      $sql_sort = ($mode == 'post_review') ? 'ASC' : 'DESC';
0904   
0905      // Go ahead and pull all data for this topic
0906      $sql = 'SELECT p.post_id
0907          FROM ' . POSTS_TABLE . ' p' . "
0908          WHERE p.topic_id = $topic_id
0909              AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . '
0910              ' . (($mode == 'post_review') ? " AND p.post_id > $cur_post_id" : '') . '
0911              ' . (($mode == 'post_review_edit') ? " AND p.post_id = $cur_post_id" : '') . '
0912          ORDER BY p.post_time ' . $sql_sort . ', p.post_id ' . $sql_sort;
0913      $result = $db->sql_query_limit($sql, $config['posts_per_page']);
0914   
0915      $post_list = array();
0916   
0917      while ($row = $db->sql_fetchrow($result))
0918      {
0919          $post_list[] = $row['post_id'];
0920      }
0921   
0922      $db->sql_freeresult($result);
0923   
0924      if (!sizeof($post_list))
0925      {
0926          return false;
0927      }
0928   
0929      // Handle 'post_review_edit' like 'post_review' from now on
0930      if ($mode == 'post_review_edit')
0931      {
0932          $mode = 'post_review';
0933      }
0934   
0935      $sql_ary = array(
0936          'SELECT'    => 'u.username, u.user_id, u.user_colour, p.*, z.friend, z.foe, uu.username as post_delete_username, uu.user_colour as post_delete_user_colour',
0937   
0938          'FROM'        => array(
0939              USERS_TABLE        => 'u',
0940              POSTS_TABLE        => 'p',
0941          ),
0942   
0943          'LEFT_JOIN'    => array(
0944              array(
0945                  'FROM'    => array(ZEBRA_TABLE => 'z'),
0946                  'ON'    => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id',
0947              ),
0948              array(
0949                  'FROM'    => array(USERS_TABLE => 'uu'),
0950                  'ON'    => 'uu.user_id = p.post_delete_user',
0951              ),
0952          ),
0953   
0954          'WHERE'        => $db->sql_in_set('p.post_id', $post_list) . '
0955              AND u.user_id = p.poster_id',
0956      );
0957   
0958      $sql = $db->sql_build_query('SELECT', $sql_ary);
0959      $result = $db->sql_query($sql);
0960   
0961      $rowset = array();
0962      $has_attachments = false;
0963      while ($row = $db->sql_fetchrow($result))
0964      {
0965          $rowset[$row['post_id']] = $row;
0966   
0967          if ($row['post_attachment'])
0968          {
0969              $has_attachments = true;
0970          }
0971      }
0972      $db->sql_freeresult($result);
0973   
0974      // Grab extensions
0975      $attachments = array();
0976      if ($has_attachments && $auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
0977      {
0978          // Get attachments...
0979          $sql = 'SELECT *
0980              FROM ' . ATTACHMENTS_TABLE . '
0981              WHERE ' . $db->sql_in_set('post_msg_id', $post_list) . '
0982                  AND in_message = 0
0983              ORDER BY filetime DESC, post_msg_id ASC';
0984          $result = $db->sql_query($sql);
0985   
0986          while ($row = $db->sql_fetchrow($result))
0987          {
0988              $attachments[$row['post_msg_id']][] = $row;
0989          }
0990          $db->sql_freeresult($result);
0991      }
0992   
0993      /**
0994      * Event to modify the posts list for topic reviews
0995      *
0996      * @event core.topic_review_modify_post_list
0997      * @var    array    attachments            Array with the post attachments data
0998      * @var    int        cur_post_id            Post offset ID
0999      * @var    int        forum_id            The topic's forum ID
1000      * @var    string    mode                The topic review mode
1001      * @var    array    post_list            Array with the post IDs
1002      * @var    array    rowset                Array with the posts data
1003      * @var    bool    show_quote_button    Flag indicating if the quote button should be displayed
1004      * @var    int        topic_id            The topic ID that is being reviewed
1005      * @since 3.1.9-RC1
1006      */
1007      $vars = array(
1008          'attachments',
1009          'cur_post_id',
1010          'forum_id',
1011          'mode',
1012          'post_list',
1013          'rowset',
1014          'show_quote_button',
1015          'topic_id',
1016      );
1017      extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_post_list', compact($vars)));
1018   
1019      for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
1020      {
1021          // A non-existing rowset only happens if there was no user present for the entered poster_id
1022          // This could be a broken posts table.
1023          if (!isset($rowset[$post_list[$i]]))
1024          {
1025              continue;
1026          }
1027   
1028          $row = $rowset[$post_list[$i]];
1029   
1030          $poster_id        = $row['user_id'];
1031          $post_subject    = $row['post_subject'];
1032   
1033          $decoded_message = false;
1034   
1035          if ($show_quote_button && $auth->acl_get('f_reply', $forum_id))
1036          {
1037              $decoded_message = censor_text($row['post_text']);
1038              decode_message($decoded_message, $row['bbcode_uid']);
1039   
1040              $decoded_message = bbcode_nl2br($decoded_message);
1041          }
1042   
1043          $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
1044          $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0);
1045          $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true);
1046   
1047          if (!empty($attachments[$row['post_id']]))
1048          {
1049              $update_count = array();
1050              parse_attachments($forum_id, $message, $attachments[$row['post_id']], $update_count);
1051          }
1052   
1053          $post_subject = censor_text($post_subject);
1054   
1055          $post_anchor = ($mode == 'post_review') ? 'ppr' . $row['post_id'] : 'pr' . $row['post_id'];
1056          $u_show_post = append_sid($phpbb_root_path . 'viewtopic.' . $phpEx, "f=$forum_id&amp;t=$topic_id&amp;p={$row['post_id']}&amp;view=show#p{$row['post_id']}");
1057   
1058          $l_deleted_message = '';
1059          if ($row['post_visibility'] == ITEM_DELETED)
1060          {
1061              $display_postername = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']);
1062   
1063              // User having deleted the post also being the post author?
1064              if (!$row['post_delete_user'] || $row['post_delete_user'] == $poster_id)
1065              {
1066                  $display_username = $display_postername;
1067              }
1068              else
1069              {
1070                  $display_username = get_username_string('full', $row['post_delete_user'], $row['post_delete_username'], $row['post_delete_user_colour']);
1071              }
1072   
1073              if ($row['post_delete_reason'])
1074              {
1075                  $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']);
1076              }
1077              else
1078              {
1079                  $l_deleted_message = $user->lang('POST_DELETED_BY', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true));
1080              }
1081          }
1082   
1083          $post_row = array(
1084              'POST_AUTHOR_FULL'        => get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1085              'POST_AUTHOR_COLOUR'    => get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1086              'POST_AUTHOR'            => get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1087              'U_POST_AUTHOR'            => get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1088   
1089              'S_HAS_ATTACHMENTS'    => (!empty($attachments[$row['post_id']])) ? true : false,
1090              'S_FRIEND'            => ($row['friend']) ? true : false,
1091              'S_IGNORE_POST'        => ($row['foe']) ? true : false,
1092              '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']), "<a href=\"{$u_show_post}\" onclick=\"phpbb.toggleDisplay('{$post_anchor}', 1); return false;\">", '</a>') : '',
1093              'S_POST_DELETED'    => ($row['post_visibility'] == ITEM_DELETED) ? true : false,
1094              'L_DELETE_POST'        => $l_deleted_message,
1095   
1096              'POST_SUBJECT'        => $post_subject,
1097              'MINI_POST_IMG'        => $user->img('icon_post_target', $user->lang['POST']),
1098              'POST_DATE'            => $user->format_date($row['post_time']),
1099              'MESSAGE'            => $message,
1100              'DECODED_MESSAGE'    => $decoded_message,
1101              'POST_ID'            => $row['post_id'],
1102              'POST_TIME'            => $row['post_time'],
1103              'USER_ID'            => $row['user_id'],
1104              'U_MINI_POST'        => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'],
1105              'U_MCP_DETAILS'        => ($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) : '',
1106              'POSTER_QUOTE'        => ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) ? addslashes(get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '',
1107          );
1108   
1109          $current_row_number = $i;
1110   
1111          /**
1112          * Event to modify the template data block for topic reviews
1113          *
1114          * @event core.topic_review_modify_row
1115          * @var    string    mode                The review mode
1116          * @var    int        topic_id            The topic that is being reviewed
1117          * @var    int        forum_id            The topic's forum
1118          * @var    int        cur_post_id            Post offset id
1119          * @var    int        current_row_number    Number of the current row being iterated
1120          * @var    array    post_row            Template block array of the current post
1121          * @var    array    row                    Array with original post and user data
1122          * @since 3.1.4-RC1
1123          */
1124          $vars = array(
1125              'mode',
1126              'topic_id',
1127              'forum_id',
1128              'cur_post_id',
1129              'current_row_number',
1130              'post_row',
1131              'row',
1132          );
1133          extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_row', compact($vars)));
1134   
1135          $template->assign_block_vars($mode . '_row', $post_row);
1136   
1137          // Display not already displayed Attachments for this post, we already parsed them. ;)
1138          if (!empty($attachments[$row['post_id']]))
1139          {
1140              foreach ($attachments[$row['post_id']] as $attachment)
1141              {
1142                  $template->assign_block_vars($mode . '_row.attachment', array(
1143                      'DISPLAY_ATTACHMENT'    => $attachment)
1144                  );
1145              }
1146          }
1147   
1148          unset($rowset[$post_list[$i]]);
1149      }
1150   
1151      if ($mode == 'topic_review')
1152      {
1153          $template->assign_var('QUOTE_IMG', $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']));
1154      }
1155   
1156      return true;
1157  }
1158   
1159  //
1160  // Post handling functions
1161  //
1162   
1163  /**
1164  * Delete Post
1165  */
1166  function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $softdelete_reason = '')
1167  {
1168      global $db, $user, $phpbb_container;
1169      global $config, $phpEx, $phpbb_root_path;
1170   
1171      // Specify our post mode
1172      $post_mode = 'delete';
1173      if (($data['topic_first_post_id'] === $data['topic_last_post_id']) && ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1))
1174      {
1175          $post_mode = 'delete_topic';
1176      }
1177      else if ($data['topic_first_post_id'] == $post_id)
1178      {
1179          $post_mode = 'delete_first_post';
1180      }
1181      else if ($data['topic_last_post_id'] == $post_id)
1182      {
1183          $post_mode = 'delete_last_post';
1184      }
1185      $sql_data = array();
1186      $next_post_id = false;
1187   
1188      include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1189   
1190      $db->sql_transaction('begin');
1191   
1192      // we must make sure to update forums that contain the shadow'd topic
1193      if ($post_mode == 'delete_topic')
1194      {
1195          $shadow_forum_ids = array();
1196   
1197          $sql = 'SELECT forum_id
1198              FROM ' . TOPICS_TABLE . '
1199              WHERE ' . $db->sql_in_set('topic_moved_id', $topic_id);
1200          $result = $db->sql_query($sql);
1201          while ($row = $db->sql_fetchrow($result))
1202          {
1203              if (!isset($shadow_forum_ids[(int) $row['forum_id']]))
1204              {
1205                  $shadow_forum_ids[(int) $row['forum_id']] = 1;
1206              }
1207              else
1208              {
1209                  $shadow_forum_ids[(int) $row['forum_id']]++;
1210              }
1211          }
1212          $db->sql_freeresult($result);
1213      }
1214   
1215      /* @var $phpbb_content_visibility \phpbb\content_visibility */
1216      $phpbb_content_visibility = $phpbb_container->get('content.visibility');
1217   
1218      // (Soft) delete the post
1219      if ($is_soft && ($post_mode != 'delete_topic'))
1220      {
1221          $phpbb_content_visibility->set_post_visibility(ITEM_DELETED, $post_id, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason, ($data['topic_first_post_id'] == $post_id), ($data['topic_last_post_id'] == $post_id));
1222      }
1223      else if (!$is_soft)
1224      {
1225          if (!delete_posts('post_id', array($post_id), false, false, false))
1226          {
1227              // Try to delete topic, we may had an previous error causing inconsistency
1228              if ($post_mode == 'delete_topic')
1229              {
1230                  delete_topics('topic_id', array($topic_id), false);
1231              }
1232              trigger_error('ALREADY_DELETED');
1233          }
1234      }
1235   
1236      $db->sql_transaction('commit');
1237   
1238      // Collect the necessary information for updating the tables
1239      $sql_data[FORUMS_TABLE] = $sql_data[TOPICS_TABLE] = '';
1240      switch ($post_mode)
1241      {
1242          case 'delete_topic':
1243   
1244              foreach ($shadow_forum_ids as $updated_forum => $topic_count)
1245              {
1246                  // counting is fun! we only have to do sizeof($forum_ids) number of queries,
1247                  // even if the topic is moved back to where its shadow lives (we count how many times it is in a forum)
1248                  $sql = 'UPDATE ' . FORUMS_TABLE . '
1249                      SET forum_topics_approved = forum_topics_approved - ' . $topic_count . '
1250                      WHERE forum_id = ' . $updated_forum;
1251                  $db->sql_query($sql);
1252                  update_post_information('forum', $updated_forum);
1253              }
1254   
1255              if ($is_soft)
1256              {
1257                  $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason);
1258              }
1259              else
1260              {
1261                  delete_topics('topic_id', array($topic_id), false);
1262   
1263                  $phpbb_content_visibility->remove_topic_from_statistic($data, $sql_data);
1264   
1265                  $update_sql = update_post_information('forum', $forum_id, true);
1266                  if (sizeof($update_sql))
1267                  {
1268                      $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : '';
1269                      $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]);
1270                  }
1271              }
1272   
1273          break;
1274   
1275          case 'delete_first_post':
1276              $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour
1277                  FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
1278                  WHERE p.topic_id = $topic_id
1279                      AND p.poster_id = u.user_id
1280                      AND p.post_visibility = " . ITEM_APPROVED . '
1281                  ORDER BY p.post_time ASC, p.post_id ASC';
1282              $result = $db->sql_query_limit($sql, 1);
1283              $row = $db->sql_fetchrow($result);
1284              $db->sql_freeresult($result);
1285   
1286              if (!$row)
1287              {
1288                  // No approved post, so the first is a not-approved post (unapproved or soft deleted)
1289                  $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour
1290                      FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
1291                      WHERE p.topic_id = $topic_id
1292                          AND p.poster_id = u.user_id
1293                      ORDER BY p.post_time ASC, p.post_id ASC";
1294                  $result = $db->sql_query_limit($sql, 1);
1295                  $row = $db->sql_fetchrow($result);
1296                  $db->sql_freeresult($result);
1297              }
1298   
1299              $next_post_id = (int) $row['post_id'];
1300   
1301              $sql_data[TOPICS_TABLE] = $db->sql_build_array('UPDATE', array(
1302                  'topic_poster'                => (int) $row['poster_id'],
1303                  'topic_first_post_id'        => (int) $row['post_id'],
1304                  'topic_first_poster_colour'    => $row['user_colour'],
1305                  'topic_first_poster_name'    => ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'],
1306                  'topic_time'                => (int) $row['post_time'],
1307              ));
1308          break;
1309   
1310          case 'delete_last_post':
1311              if (!$is_soft)
1312              {
1313                  // Update last post information when hard deleting. Soft delete already did that by itself.
1314                  $update_sql = update_post_information('forum', $forum_id, true);
1315                  if (sizeof($update_sql))
1316                  {
1317                      $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . implode(', ', $update_sql[$forum_id]);
1318                  }
1319   
1320                  $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_bumped = 0, topic_bumper = 0';
1321   
1322                  $update_sql = update_post_information('topic', $topic_id, true);
1323                  if (!empty($update_sql))
1324                  {
1325                      $sql_data[TOPICS_TABLE] .= ', ' . implode(', ', $update_sql[$topic_id]);
1326                      $next_post_id = (int) str_replace('topic_last_post_id = ', '', $update_sql[$topic_id][0]);
1327                  }
1328              }
1329   
1330              if (!$next_post_id)
1331              {
1332                  $sql = 'SELECT MAX(post_id) as last_post_id
1333                      FROM ' . POSTS_TABLE . "
1334                      WHERE topic_id = $topic_id
1335                          AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id);
1336                  $result = $db->sql_query($sql);
1337                  $next_post_id = (int) $db->sql_fetchfield('last_post_id');
1338                  $db->sql_freeresult($result);
1339              }
1340          break;
1341   
1342          case 'delete':
1343              $sql = 'SELECT post_id
1344                  FROM ' . POSTS_TABLE . "
1345                  WHERE topic_id = $topic_id
1346                      AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . '
1347                      AND post_time > ' . $data['post_time'] . '
1348                  ORDER BY post_time ASC, post_id ASC';
1349              $result = $db->sql_query_limit($sql, 1);
1350              $next_post_id = (int) $db->sql_fetchfield('post_id');
1351              $db->sql_freeresult($result);
1352          break;
1353      }
1354   
1355      if (($post_mode == 'delete') || ($post_mode == 'delete_last_post') || ($post_mode == 'delete_first_post'))
1356      {
1357          if (!$is_soft)
1358          {
1359              $phpbb_content_visibility->remove_post_from_statistic($data, $sql_data);
1360          }
1361   
1362          $sql = 'SELECT 1 AS has_attachments
1363              FROM ' . ATTACHMENTS_TABLE . '
1364              WHERE topic_id = ' . $topic_id;
1365          $result = $db->sql_query_limit($sql, 1);
1366          $has_attachments = (int) $db->sql_fetchfield('has_attachments');
1367          $db->sql_freeresult($result);
1368   
1369          if (!$has_attachments)
1370          {
1371              $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_attachment = 0';
1372          }
1373      }
1374   
1375      $db->sql_transaction('begin');
1376   
1377      $where_sql = array(
1378          FORUMS_TABLE    => "forum_id = $forum_id",
1379          TOPICS_TABLE    => "topic_id = $topic_id",
1380          USERS_TABLE        => 'user_id = ' . $data['poster_id'],
1381      );
1382   
1383      foreach ($sql_data as $table => $update_sql)
1384      {
1385          if ($update_sql)
1386          {
1387              $db->sql_query("UPDATE $table SET $update_sql WHERE " . $where_sql[$table]);
1388          }
1389      }
1390   
1391      // Adjust posted info for this user by looking for a post by him/her within this topic...
1392      if ($post_mode != 'delete_topic' && $config['load_db_track'] && $data['poster_id'] != ANONYMOUS)
1393      {
1394          $sql = 'SELECT poster_id
1395              FROM ' . POSTS_TABLE . '
1396              WHERE topic_id = ' . $topic_id . '
1397                  AND poster_id = ' . $data['poster_id'];
1398          $result = $db->sql_query_limit($sql, 1);
1399          $poster_id = (int) $db->sql_fetchfield('poster_id');
1400          $db->sql_freeresult($result);
1401   
1402          // The user is not having any more posts within this topic
1403          if (!$poster_id)
1404          {
1405              $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . '
1406                  WHERE topic_id = ' . $topic_id . '
1407                      AND user_id = ' . $data['poster_id'];
1408              $db->sql_query($sql);
1409          }
1410      }
1411   
1412      $db->sql_transaction('commit');
1413   
1414      if ($data['post_reported'] && ($post_mode != 'delete_topic'))
1415      {
1416          sync('topic_reported', 'topic_id', array($topic_id));
1417      }
1418   
1419      return $next_post_id;
1420  }
1421   
1422  /**
1423  * Submit Post
1424  * @todo Split up and create lightweight, simple API for this.
1425  */
1426  function submit_post($mode, $subject, $username, $topic_type, &$poll_ary, &$data_ary, $update_message = true, $update_search_index = true)
1427  {
1428      global $db, $auth, $user, $config, $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $phpbb_log, $request;
1429   
1430      $poll = $poll_ary;
1431      $data = $data_ary;
1432      /**
1433      * Modify the data for post submitting
1434      *
1435      * @event core.modify_submit_post_data
1436      * @var    string    mode                Variable containing posting mode value
1437      * @var    string    subject                Variable containing post subject value
1438      * @var    string    username            Variable containing post author name
1439      * @var    int        topic_type            Variable containing topic type value
1440      * @var    array    poll                Array with the poll data for the post
1441      * @var    array    data                Array with the data for the post
1442      * @var    bool    update_message        Flag indicating if the post will be updated
1443      * @var    bool    update_search_index    Flag indicating if the search index will be updated
1444      * @since 3.1.0-a4
1445      */
1446      $vars = array(
1447          'mode',
1448          'subject',
1449          'username',
1450          'topic_type',
1451          'poll',
1452          'data',
1453          'update_message',
1454          'update_search_index',
1455      );
1456      extract($phpbb_dispatcher->trigger_event('core.modify_submit_post_data', compact($vars)));
1457      $poll_ary = $poll;
1458      $data_ary = $data;
1459      unset($poll);
1460      unset($data);
1461   
1462      // We do not handle erasing posts here
1463      if ($mode == 'delete')
1464      {
1465          return false;
1466      }
1467   
1468      if (!empty($data_ary['post_time']))
1469      {
1470          $current_time = $data_ary['post_time'];
1471      }
1472      else
1473      {
1474          $current_time = time();
1475      }
1476   
1477      if ($mode == 'post')
1478      {
1479          $post_mode = 'post';
1480          $update_message = true;
1481      }
1482      else if ($mode != 'edit')
1483      {
1484          $post_mode = 'reply';
1485          $update_message = true;
1486      }
1487      else if ($mode == 'edit')
1488      {
1489          $post_mode = ($data_ary['topic_posts_approved'] + $data_ary['topic_posts_unapproved'] + $data_ary['topic_posts_softdeleted'] == 1) ? 'edit_topic' : (($data_ary['topic_first_post_id'] == $data_ary['post_id']) ? 'edit_first_post' : (($data_ary['topic_last_post_id'] == $data_ary['post_id']) ? 'edit_last_post' : 'edit'));
1490      }
1491   
1492      // First of all make sure the subject and topic title are having the correct length.
1493      // To achieve this without cutting off between special chars we convert to an array and then count the elements.
1494      $subject = truncate_string($subject, 120);
1495      $data_ary['topic_title'] = truncate_string($data_ary['topic_title'], 120);
1496   
1497      // Collect some basic information about which tables and which rows to update/insert
1498      $sql_data = $topic_row = array();
1499      $poster_id = ($mode == 'edit') ? $data_ary['poster_id'] : (int) $user->data['user_id'];
1500   
1501      // Retrieve some additional information if not present
1502      if ($mode == 'edit' && (!isset($data_ary['post_visibility']) || !isset($data_ary['topic_visibility']) || $data_ary['post_visibility'] === false || $data_ary['topic_visibility'] === false))
1503      {
1504          $sql = 'SELECT p.post_visibility, t.topic_type, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_visibility
1505              FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p
1506              WHERE t.topic_id = p.topic_id
1507                  AND p.post_id = ' . $data_ary['post_id'];
1508          $result = $db->sql_query($sql);
1509          $topic_row = $db->sql_fetchrow($result);
1510          $db->sql_freeresult($result);
1511   
1512          $data_ary['topic_visibility'] = $topic_row['topic_visibility'];
1513          $data_ary['post_visibility'] = $topic_row['post_visibility'];
1514      }
1515   
1516      // This variable indicates if the user is able to post or put into the queue
1517      $post_visibility = ITEM_APPROVED;
1518   
1519      // Check the permissions for post approval.
1520      // Moderators must go through post approval like ordinary users.
1521      if (!$auth->acl_get('f_noapprove', $data_ary['forum_id']))
1522      {
1523          // Post not approved, but in queue
1524          $post_visibility = ITEM_UNAPPROVED;
1525          switch ($post_mode)
1526          {
1527              case 'edit_first_post':
1528              case 'edit':
1529              case 'edit_last_post':
1530              case 'edit_topic':
1531                  $post_visibility = ITEM_REAPPROVE;
1532              break;
1533          }
1534      }
1535      else if (isset($data_ary['post_visibility']) && $data_ary['post_visibility'] !== false)
1536      {
1537          $post_visibility = $data_ary['post_visibility'];
1538      }
1539   
1540      // MODs/Extensions are able to force any visibility on posts
1541      if (isset($data_ary['force_approved_state']))
1542      {
1543          $post_visibility = (in_array((int) $data_ary['force_approved_state'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data_ary['force_approved_state'] : $post_visibility;
1544      }
1545      if (isset($data_ary['force_visibility']))
1546      {
1547          $post_visibility = (in_array((int) $data_ary['force_visibility'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data_ary['force_visibility'] : $post_visibility;
1548      }
1549   
1550      // Start the transaction here
1551      $db->sql_transaction('begin');
1552   
1553      // Collect Information
1554      switch ($post_mode)
1555      {
1556          case 'post':
1557          case 'reply':
1558              $sql_data[POSTS_TABLE]['sql'] = array(
1559                  'forum_id'            => $data_ary['forum_id'],
1560                  'poster_id'            => (int) $user->data['user_id'],
1561                  'icon_id'            => $data_ary['icon_id'],
1562                  'poster_ip'            => $user->ip,
1563                  'post_time'            => $current_time,
1564                  'post_visibility'    => $post_visibility,
1565                  'enable_bbcode'        => $data_ary['enable_bbcode'],
1566                  'enable_smilies'    => $data_ary['enable_smilies'],
1567                  'enable_magic_url'    => $data_ary['enable_urls'],
1568                  'enable_sig'        => $data_ary['enable_sig'],
1569                  'post_username'        => (!$user->data['is_registered']) ? $username : '',
1570                  'post_subject'        => $subject,
1571                  'post_text'            => $data_ary['message'],
1572                  'post_checksum'        => $data_ary['message_md5'],
1573                  'post_attachment'    => (!empty($data_ary['attachment_data'])) ? 1 : 0,
1574                  'bbcode_bitfield'    => $data_ary['bbcode_bitfield'],
1575                  'bbcode_uid'        => $data_ary['bbcode_uid'],
1576                  'post_postcount'    => ($auth->acl_get('f_postcount', $data_ary['forum_id'])) ? 1 : 0,
1577                  'post_edit_locked'    => $data_ary['post_edit_locked']
1578              );
1579          break;
1580   
1581          case 'edit_first_post':
1582          case 'edit':
1583   
1584          case 'edit_last_post':
1585          case 'edit_topic':
1586   
1587              // If edit reason is given always display edit info
1588   
1589              // If editing last post then display no edit info
1590              // If m_edit permission then display no edit info
1591              // If normal edit display edit info
1592   
1593              // Display edit info if edit reason given or user is editing his post, which is not the last within the topic.
1594              if ($data_ary['post_edit_reason'] || (!$auth->acl_get('m_edit', $data_ary['forum_id']) && ($post_mode == 'edit' || $post_mode == 'edit_first_post')))
1595              {
1596                  $data_ary['post_edit_reason']        = truncate_string($data_ary['post_edit_reason'], 255, 255, false);
1597   
1598                  $sql_data[POSTS_TABLE]['sql']    = array(
1599                      'post_edit_time'    => $current_time,
1600                      'post_edit_reason'    => $data_ary['post_edit_reason'],
1601                      'post_edit_user'    => (int) $data_ary['post_edit_user'],
1602                  );
1603   
1604                  $sql_data[POSTS_TABLE]['stat'][] = 'post_edit_count = post_edit_count + 1';
1605              }
1606              else if (!$data_ary['post_edit_reason'] && $mode == 'edit' && $auth->acl_get('m_edit', $data_ary['forum_id']))
1607              {
1608                  $sql_data[POSTS_TABLE]['sql'] = array(
1609                      'post_edit_reason'    => '',
1610                  );
1611              }
1612   
1613              // If the person editing this post is different to the one having posted then we will add a log entry stating the edit
1614              // Could be simplified by only adding to the log if the edit is not tracked - but this may confuse admins/mods
1615              if ($user->data['user_id'] != $poster_id)
1616              {
1617                  $log_subject = ($subject) ? $subject : $data_ary['topic_title'];
1618                  $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_POST_EDITED', false, array(
1619                      'forum_id' => $data_ary['forum_id'],
1620                      'topic_id' => $data_ary['topic_id'],
1621                      'post_id'  => $data_ary['post_id'],
1622                      $log_subject,
1623                      (!empty($username)) ? $username : $user->lang['GUEST'],
1624                      $data_ary['post_edit_reason']
1625                  ));
1626              }
1627   
1628              if (!isset($sql_data[POSTS_TABLE]['sql']))
1629              {
1630                  $sql_data[POSTS_TABLE]['sql'] = array();
1631              }
1632   
1633              $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
1634                  'forum_id'            => $data_ary['forum_id'],
1635                  'poster_id'            => $data_ary['poster_id'],
1636                  'icon_id'            => $data_ary['icon_id'],
1637                  // We will change the visibility later
1638                  //'post_visibility'    => $post_visibility,
1639                  'enable_bbcode'        => $data_ary['enable_bbcode'],
1640                  'enable_smilies'    => $data_ary['enable_smilies'],
1641                  'enable_magic_url'    => $data_ary['enable_urls'],
1642                  'enable_sig'        => $data_ary['enable_sig'],
1643                  'post_username'        => ($username && $data_ary['poster_id'] == ANONYMOUS) ? $username : '',
1644                  'post_subject'        => $subject,
1645                  'post_checksum'        => $data_ary['message_md5'],
1646                  'post_attachment'    => (!empty($data_ary['attachment_data'])) ? 1 : 0,
1647                  'bbcode_bitfield'    => $data_ary['bbcode_bitfield'],
1648                  'bbcode_uid'        => $data_ary['bbcode_uid'],
1649                  'post_edit_locked'    => $data_ary['post_edit_locked'])
1650              );
1651   
1652              if ($update_message)
1653              {
1654                  $sql_data[POSTS_TABLE]['sql']['post_text'] = $data_ary['message'];
1655              }
1656   
1657          break;
1658      }
1659   
1660      // And the topic ladies and gentlemen
1661      switch ($post_mode)
1662      {
1663          case 'post':
1664              $sql_data[TOPICS_TABLE]['sql'] = array(
1665                  'topic_poster'                => (int) $user->data['user_id'],
1666                  'topic_time'                => $current_time,
1667                  'topic_last_view_time'        => $current_time,
1668                  'forum_id'                    => $data_ary['forum_id'],
1669                  'icon_id'                    => $data_ary['icon_id'],
1670                  'topic_posts_approved'        => ($post_visibility == ITEM_APPROVED) ? 1 : 0,
1671                  'topic_posts_softdeleted'    => ($post_visibility == ITEM_DELETED) ? 1 : 0,
1672                  'topic_posts_unapproved'    => ($post_visibility == ITEM_UNAPPROVED) ? 1 : 0,
1673                  'topic_visibility'            => $post_visibility,
1674                  'topic_delete_user'            => ($post_visibility != ITEM_APPROVED) ? (int) $user->data['user_id'] : 0,
1675                  'topic_title'                => $subject,
1676                  'topic_first_poster_name'    => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''),
1677                  'topic_first_poster_colour'    => $user->data['user_colour'],
1678                  'topic_type'                => $topic_type,
1679                  'topic_time_limit'            => ($topic_type == POST_STICKY || $topic_type == POST_ANNOUNCE) ? ($data_ary['topic_time_limit'] * 86400) : 0,
1680                  'topic_attachment'            => (!empty($data_ary['attachment_data'])) ? 1 : 0,
1681                  'topic_status'                => (isset($data_ary['topic_status'])) ? $data_ary['topic_status'] : ITEM_UNLOCKED,
1682              );
1683   
1684              if (isset($poll_ary['poll_options']) && !empty($poll_ary['poll_options']))
1685              {
1686                  $poll_start = ($poll_ary['poll_start']) ? $poll_ary['poll_start'] : $current_time;
1687                  $poll_length = $poll_ary['poll_length'] * 86400;
1688                  if ($poll_length < 0)
1689                  {
1690                      $poll_start = $poll_start + $poll_length;
1691                      if ($poll_start < 0)
1692                      {
1693                          $poll_start = 0;
1694                      }
1695                      $poll_length = 1;
1696                  }
1697   
1698                  $sql_data[TOPICS_TABLE]['sql'] = array_merge($sql_data[TOPICS_TABLE]['sql'], array(
1699                      'poll_title'        => $poll_ary['poll_title'],
1700                      'poll_start'        => $poll_start,
1701                      'poll_max_options'    => $poll_ary['poll_max_options'],
1702                      'poll_length'        => $poll_length,
1703                      'poll_vote_change'    => $poll_ary['poll_vote_change'])
1704                  );
1705              }
1706   
1707              $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data_ary['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
1708   
1709              if ($post_visibility == ITEM_APPROVED)
1710              {
1711                  $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_approved = forum_topics_approved + 1';
1712                  $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1';
1713              }
1714              else if ($post_visibility == ITEM_UNAPPROVED)
1715              {
1716                  $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_unapproved = forum_topics_unapproved + 1';
1717                  $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1';
1718              }
1719              else if ($post_visibility == ITEM_DELETED)
1720              {
1721                  $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_softdeleted = forum_topics_softdeleted + 1';
1722                  $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1';
1723              }
1724          break;
1725   
1726          case 'reply':
1727              $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_view_time = ' . $current_time . ',
1728                  topic_bumped = 0,
1729                  topic_bumper = 0' .
1730                  (($post_visibility == ITEM_APPROVED) ? ', topic_posts_approved = topic_posts_approved + 1' : '') .
1731                  (($post_visibility == ITEM_UNAPPROVED) ? ', topic_posts_unapproved = topic_posts_unapproved + 1' : '') .
1732                  (($post_visibility == ITEM_DELETED) ? ', topic_posts_softdeleted = topic_posts_softdeleted + 1' : '') .
1733                  ((!empty($data_ary['attachment_data']) || (isset($data_ary['topic_attachment']) && $data_ary['topic_attachment'])) ? ', topic_attachment = 1' : '');
1734   
1735              $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data_ary['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
1736   
1737              if ($post_visibility == ITEM_APPROVED)
1738              {
1739                  $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1';
1740              }
1741              else if ($post_visibility == ITEM_UNAPPROVED)
1742              {
1743                  $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1';
1744              }
1745              else if ($post_visibility == ITEM_DELETED)
1746              {
1747                  $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1';
1748              }
1749          break;
1750   
1751          case 'edit_topic':
1752          case 'edit_first_post':
1753              if (isset($poll_ary['poll_options']))
1754              {
1755                  $poll_start = ($poll_ary['poll_start'] || empty($poll_ary['poll_options'])) ? $poll_ary['poll_start'] : $current_time;
1756                  $poll_length = $poll_ary['poll_length'] * 86400;
1757                  if ($poll_length < 0)
1758                  {
1759                      $poll_start = $poll_start + $poll_length;
1760                      if ($poll_start < 0)
1761                      {
1762                          $poll_start = 0;
1763                      }
1764                      $poll_length = 1;
1765                  }
1766              }
1767   
1768              $sql_data[TOPICS_TABLE]['sql'] = array(
1769                  'forum_id'                    => $data_ary['forum_id'],
1770                  'icon_id'                    => $data_ary['icon_id'],
1771                  'topic_title'                => $subject,
1772                  'topic_first_poster_name'    => $username,
1773                  'topic_type'                => $topic_type,
1774                  'topic_time_limit'            => ($topic_type == POST_STICKY || $topic_type == POST_ANNOUNCE) ? ($data_ary['topic_time_limit'] * 86400) : 0,
1775                  'poll_title'                => (isset($poll_ary['poll_options'])) ? $poll_ary['poll_title'] : '',
1776                  'poll_start'                => (isset($poll_ary['poll_options'])) ? $poll_start : 0,
1777                  'poll_max_options'            => (isset($poll_ary['poll_options'])) ? $poll_ary['poll_max_options'] : 1,
1778                  'poll_length'                => (isset($poll_ary['poll_options'])) ? $poll_length : 0,
1779                  'poll_vote_change'            => (isset($poll_ary['poll_vote_change'])) ? $poll_ary['poll_vote_change'] : 0,
1780                  'topic_last_view_time'        => $current_time,
1781   
1782                  'topic_attachment'            => (!empty($data_ary['attachment_data'])) ? 1 : (isset($data_ary['topic_attachment']) ? $data_ary['topic_attachment'] : 0),
1783              );
1784   
1785          break;
1786      }
1787   
1788      $poll = $poll_ary;
1789      $data = $data_ary;
1790      /**
1791      * Modify sql query data for post submitting
1792      *
1793      * @event core.submit_post_modify_sql_data
1794      * @var    array    data                Array with the data for the post
1795      * @var    array    poll                Array with the poll data for the post
1796      * @var    string    post_mode            Variable containing posting mode value
1797      * @var    bool    sql_data            Array with the data for the posting SQL query
1798      * @var    string    subject                Variable containing post subject value
1799      * @var    int        topic_type            Variable containing topic type value
1800      * @var    string    username            Variable containing post author name
1801      * @since 3.1.3-RC1
1802      */
1803      $vars = array(
1804          'data',
1805          'poll',
1806          'post_mode',
1807          'sql_data',
1808          'subject',
1809          'topic_type',
1810          'username',
1811      );
1812      extract($phpbb_dispatcher->trigger_event('core.submit_post_modify_sql_data', compact($vars)));
1813      $poll_ary = $poll;
1814      $data_ary = $data;
1815      unset($poll);
1816      unset($data);
1817   
1818      // Submit new topic
1819      if ($post_mode == 'post')
1820      {
1821          $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' .
1822              $db->sql_build_array('INSERT', $sql_data[TOPICS_TABLE]['sql']);
1823          $db->sql_query($sql);
1824   
1825          $data_ary['topic_id'] = $db->sql_nextid();
1826   
1827          $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
1828              'topic_id' => $data_ary['topic_id'])
1829          );
1830          unset($sql_data[TOPICS_TABLE]['sql']);
1831      }
1832   
1833      // Submit new post
1834      if ($post_mode == 'post' || $post_mode == 'reply')
1835      {
1836          if ($post_mode == 'reply')
1837          {
1838              $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
1839                  'topic_id' => $data_ary['topic_id'],
1840              ));
1841          }
1842   
1843          $sql = 'INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data[POSTS_TABLE]['sql']);
1844          $db->sql_query($sql);
1845          $data_ary['post_id'] = $db->sql_nextid();
1846   
1847          if ($post_mode == 'post' || $post_visibility == ITEM_APPROVED)
1848          {
1849              $sql_data[TOPICS_TABLE]['sql'] = array(
1850                  'topic_last_post_id'        => $data_ary['post_id'],
1851                  'topic_last_post_time'        => $current_time,
1852                  'topic_last_poster_id'        => $sql_data[POSTS_TABLE]['sql']['poster_id'],
1853                  'topic_last_poster_name'    => ($user->data['user_id'] == ANONYMOUS) ? $sql_data[POSTS_TABLE]['sql']['post_username'] : $user->data['username'],
1854                  'topic_last_poster_colour'    => $user->data['user_colour'],
1855                  'topic_last_post_subject'    => (string) $subject,
1856              );
1857          }
1858   
1859          if ($post_mode == 'post')
1860          {
1861              $sql_data[TOPICS_TABLE]['sql']['topic_first_post_id'] = $data_ary['post_id'];
1862          }
1863   
1864          // Update total post count and forum information
1865          if ($post_visibility == ITEM_APPROVED)
1866          {
1867              if ($post_mode == 'post')
1868              {
1869                  $config->increment('num_topics', 1, false);
1870              }
1871              $config->increment('num_posts', 1, false);
1872   
1873              $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . $data_ary['post_id'];
1874              $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
1875              $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . $current_time;
1876              $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $user->data['user_id'];
1877              $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'";
1878              $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($user->data['user_colour']) . "'";
1879          }
1880   
1881          unset($sql_data[POSTS_TABLE]['sql']);
1882      }
1883   
1884      // Update the topics table
1885      if (isset($sql_data[TOPICS_TABLE]['sql']))
1886      {
1887          $sql = 'UPDATE ' . TOPICS_TABLE . '
1888              SET ' . $db->sql_build_array('UPDATE', $sql_data[TOPICS_TABLE]['sql']) . '
1889              WHERE topic_id = ' . $data_ary['topic_id'];
1890          $db->sql_query($sql);
1891   
1892          unset($sql_data[TOPICS_TABLE]['sql']);
1893      }
1894   
1895      // Update the posts table
1896      if (isset($sql_data[POSTS_TABLE]['sql']))
1897      {
1898          $sql = 'UPDATE ' . POSTS_TABLE . '
1899              SET ' . $db->sql_build_array('UPDATE', $sql_data[POSTS_TABLE]['sql']) . '
1900              WHERE post_id = ' . $data_ary['post_id'];
1901          $db->sql_query($sql);
1902   
1903          unset($sql_data[POSTS_TABLE]['sql']);
1904      }
1905   
1906      // Update Poll Tables
1907      if (isset($poll_ary['poll_options']))
1908      {
1909          $cur_poll_options = array();
1910   
1911          if ($mode == 'edit')
1912          {
1913              $sql = 'SELECT *
1914                  FROM ' . POLL_OPTIONS_TABLE . '
1915                  WHERE topic_id = ' . $data_ary['topic_id'] . '
1916                  ORDER BY poll_option_id';
1917              $result = $db->sql_query($sql);
1918   
1919              $cur_poll_options = array();
1920              while ($row = $db->sql_fetchrow($result))
1921              {
1922                  $cur_poll_options[] = $row;
1923              }
1924              $db->sql_freeresult($result);
1925          }
1926   
1927          $sql_insert_ary = array();
1928   
1929          for ($i = 0, $size = sizeof($poll_ary['poll_options']); $i < $size; $i++)
1930          {
1931              if (strlen(trim($poll_ary['poll_options'][$i])))
1932              {
1933                  if (empty($cur_poll_options[$i]))
1934                  {
1935                      // If we add options we need to put them to the end to be able to preserve votes...
1936                      $sql_insert_ary[] = array(
1937                          'poll_option_id'    => (int) sizeof($cur_poll_options) + 1 + sizeof($sql_insert_ary),
1938                          'topic_id'            => (int) $data_ary['topic_id'],
1939                          'poll_option_text'    => (string) $poll_ary['poll_options'][$i]
1940                      );
1941                  }
1942                  else if ($poll_ary['poll_options'][$i] != $cur_poll_options[$i])
1943                  {
1944                      $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . "
1945                          SET poll_option_text = '" . $db->sql_escape($poll_ary['poll_options'][$i]) . "'
1946                          WHERE poll_option_id = " . $cur_poll_options[$i]['poll_option_id'] . '
1947                              AND topic_id = ' . $data_ary['topic_id'];
1948                      $db->sql_query($sql);
1949                  }
1950              }
1951          }
1952   
1953          $db->sql_multi_insert(POLL_OPTIONS_TABLE, $sql_insert_ary);
1954   
1955          if (sizeof($poll_ary['poll_options']) < sizeof($cur_poll_options))
1956          {
1957              $sql = 'DELETE FROM ' . POLL_OPTIONS_TABLE . '
1958                  WHERE poll_option_id > ' . sizeof($poll_ary['poll_options']) . '
1959                      AND topic_id = ' . $data_ary['topic_id'];
1960              $db->sql_query($sql);
1961          }
1962   
1963          // If edited, we would need to reset votes (since options can be re-ordered above, you can't be sure if the change is for changing the text or adding an option
1964          if ($mode == 'edit' && sizeof($poll_ary['poll_options']) != sizeof($cur_poll_options))
1965          {
1966              $db->sql_query('DELETE FROM ' . POLL_VOTES_TABLE . ' WHERE topic_id = ' . $data_ary['topic_id']);
1967              $db->sql_query('UPDATE ' . POLL_OPTIONS_TABLE . ' SET poll_option_total = 0 WHERE topic_id = ' . $data_ary['topic_id']);
1968          }
1969      }
1970   
1971      // Submit Attachments
1972      if (!empty($data_ary['attachment_data']) && $data_ary['post_id'] && in_array($mode, array('post', 'reply', 'quote', 'edit')))
1973      {
1974          $space_taken = $files_added = 0;
1975          $orphan_rows = array();
1976   
1977          foreach ($data_ary['attachment_data'] as $pos => $attach_row)
1978          {
1979              $orphan_rows[(int) $attach_row['attach_id']] = array();
1980          }
1981   
1982          if (sizeof($orphan_rows))
1983          {
1984              $sql = 'SELECT attach_id, filesize, physical_filename
1985                  FROM ' . ATTACHMENTS_TABLE . '
1986                  WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
1987                      AND is_orphan = 1
1988                      AND poster_id = ' . $user->data['user_id'];
1989              $result = $db->sql_query($sql);
1990   
1991              $orphan_rows = array();
1992              while ($row = $db->sql_fetchrow($result))
1993              {
1994                  $orphan_rows[$row['attach_id']] = $row;
1995              }
1996              $db->sql_freeresult($result);
1997          }
1998   
1999          foreach ($data_ary['attachment_data'] as $pos => $attach_row)
2000          {
2001              if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
2002              {
2003                  continue;
2004              }
2005   
2006              if (!$attach_row['is_orphan'])
2007              {
2008                  // update entry in db if attachment already stored in db and filespace
2009                  $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
2010                      SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "'
2011                      WHERE attach_id = " . (int) $attach_row['attach_id'] . '
2012                          AND is_orphan = 0';
2013                  $db->sql_query($sql);
2014              }
2015              else
2016              {
2017                  // insert attachment into db
2018                  if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
2019                  {
2020                      continue;
2021                  }
2022   
2023                  $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
2024                  $files_added++;
2025   
2026                  $attach_sql = array(
2027                      'post_msg_id'        => $data_ary['post_id'],
2028                      'topic_id'            => $data_ary['topic_id'],
2029                      'is_orphan'            => 0,
2030                      'poster_id'            => $poster_id,
2031                      'attach_comment'    => $attach_row['attach_comment'],
2032                  );
2033   
2034                  $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . '
2035                      WHERE attach_id = ' . $attach_row['attach_id'] . '
2036                          AND is_orphan = 1
2037                          AND poster_id = ' . $user->data['user_id'];
2038                  $db->sql_query($sql);
2039              }
2040          }
2041   
2042          if ($space_taken && $files_added)
2043          {
2044              $config->increment('upload_dir_size', $space_taken, false);
2045              $config->increment('num_files', $files_added, false);
2046          }
2047      }
2048   
2049      $first_post_has_topic_info = ($post_mode == 'edit_first_post' &&
2050              (($post_visibility == ITEM_DELETED && $data_ary['topic_posts_softdeleted'] == 1) ||
2051              ($post_visibility == ITEM_UNAPPROVED && $data_ary['topic_posts_unapproved'] == 1) ||
2052              ($post_visibility == ITEM_REAPPROVE && $data_ary['topic_posts_unapproved'] == 1) ||
2053              ($post_visibility == ITEM_APPROVED && $data_ary['topic_posts_approved'] == 1)));
2054      // Fix the post's and topic's visibility and first/last post information, when the post is edited
2055      if (($post_mode != 'post' && $post_mode != 'reply') && $data_ary['post_visibility'] != $post_visibility)
2056      {
2057          // If the post was not approved, it could also be the starter,
2058          // so we sync the starter after approving/restoring, to ensure that the stats are correct
2059          // Same applies for the last post
2060          $is_starter = ($post_mode == 'edit_first_post' || $post_mode == 'edit_topic' || $data_ary['post_visibility'] != ITEM_APPROVED);
2061          $is_latest = ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $data_ary['post_visibility'] != ITEM_APPROVED);
2062   
2063          /* @var $phpbb_content_visibility \phpbb\content_visibility */
2064          $phpbb_content_visibility = $phpbb_container->get('content.visibility');
2065          $phpbb_content_visibility->set_post_visibility($post_visibility, $data_ary['post_id'], $data_ary['topic_id'], $data_ary['forum_id'], $user->data['user_id'], time(), '', $is_starter, $is_latest);
2066      }
2067      else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $first_post_has_topic_info)
2068      {
2069          if ($post_visibility == ITEM_APPROVED || $data_ary['topic_visibility'] == $post_visibility)
2070          {
2071              // only the subject can be changed from edit
2072              $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'";
2073   
2074              // Maybe not only the subject, but also changing anonymous usernames. ;)
2075              if ($data_ary['poster_id'] == ANONYMOUS)
2076              {
2077                  $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape($username) . "'";
2078              }
2079   
2080              if ($post_visibility == ITEM_APPROVED)
2081              {
2082                  // this does not _necessarily_ mean that we must update the info again,
2083                  // it just means that we might have to
2084                  $sql = 'SELECT forum_last_post_id, forum_last_post_subject
2085                      FROM ' . FORUMS_TABLE . '
2086                      WHERE forum_id = ' . (int) $data_ary['forum_id'];
2087                  $result = $db->sql_query($sql);
2088                  $row = $db->sql_fetchrow($result);
2089                  $db->sql_freeresult($result);
2090   
2091                  // this post is the latest post in the forum, better update
2092                  if ($row['forum_last_post_id'] == $data_ary['post_id'] && ($row['forum_last_post_subject'] !== $subject || $data_ary['poster_id'] == ANONYMOUS))
2093                  {
2094                      // the post's subject changed
2095                      if ($row['forum_last_post_subject'] !== $subject)
2096                      {
2097                          $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
2098                      }
2099   
2100                      // Update the user name if poster is anonymous... just in case a moderator changed it
2101                      if ($data_ary['poster_id'] == ANONYMOUS)
2102                      {
2103                          $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'";
2104                      }
2105                  }
2106              }
2107          }
2108      }
2109   
2110      // Update forum stats
2111      $where_sql = array(
2112          POSTS_TABLE        => 'post_id = ' . $data_ary['post_id'],
2113          TOPICS_TABLE    => 'topic_id = ' . $data_ary['topic_id'],
2114          FORUMS_TABLE    => 'forum_id = ' . $data_ary['forum_id'],
2115          USERS_TABLE        => 'user_id = ' . $poster_id
2116      );
2117   
2118      foreach ($sql_data as $table => $update_ary)
2119      {
2120          if (isset($update_ary['stat']) && implode('', $update_ary['stat']))
2121          {
2122              $sql = "UPDATE $table SET " . implode(', ', $update_ary['stat']) . ' WHERE ' . $where_sql[$table];
2123              $db->sql_query($sql);
2124          }
2125      }
2126   
2127      // Delete topic shadows (if any exist). We do not need a shadow topic for an global announcement
2128      if ($topic_type == POST_GLOBAL)
2129      {
2130          $sql = 'DELETE FROM ' . TOPICS_TABLE . '
2131              WHERE topic_moved_id = ' . $data_ary['topic_id'];
2132          $db->sql_query($sql);
2133      }
2134   
2135      // Committing the transaction before updating search index
2136      $db->sql_transaction('commit');
2137   
2138      // Delete draft if post was loaded...
2139      $draft_id = $request->variable('draft_loaded', 0);
2140      if ($draft_id)
2141      {
2142          $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
2143              WHERE draft_id = $draft_id
2144                  AND user_id = {$user->data['user_id']}";
2145          $db->sql_query($sql);
2146      }
2147   
2148      // Index message contents
2149      if ($update_search_index && $data_ary['enable_indexing'])
2150      {
2151          // Select the search method and do some additional checks to ensure it can actually be utilised
2152          $search_type = $config['search_type'];
2153   
2154          if (!class_exists($search_type))
2155          {
2156              trigger_error('NO_SUCH_SEARCH_MODULE');
2157          }
2158   
2159          $error = false;
2160          $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
2161   
2162          if ($error)
2163          {
2164              trigger_error($error);
2165          }
2166   
2167          $search->index($mode, $data_ary['post_id'], $data_ary['message'], $subject, $poster_id, $data_ary['forum_id']);
2168      }
2169   
2170      // Topic Notification, do not change if moderator is changing other users posts...
2171      if ($user->data['user_id'] == $poster_id)
2172      {
2173          if (!$data_ary['notify_set'] && $data_ary['notify'])
2174          {
2175              $sql = 'INSERT INTO ' . TOPICS_WATCH_TABLE . ' (user_id, topic_id)
2176                  VALUES (' . $user->data['user_id'] . ', ' . $data_ary['topic_id'] . ')';
2177              $db->sql_query($sql);
2178          }
2179          else if (($config['email_enable'] || $config['jab_enable']) && $data_ary['notify_set'] && !$data_ary['notify'])
2180          {
2181              $sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . '
2182                  WHERE user_id = ' . $user->data['user_id'] . '
2183                      AND topic_id = ' . $data_ary['topic_id'];
2184              $db->sql_query($sql);
2185          }
2186      }
2187   
2188      if ($mode == 'post' || $mode == 'reply' || $mode == 'quote')
2189      {
2190          // Mark this topic as posted to
2191          markread('post', $data_ary['forum_id'], $data_ary['topic_id']);
2192      }
2193   
2194      // Mark this topic as read
2195      // We do not use post_time here, this is intended (post_time can have a date in the past if editing a message)
2196      markread('topic', $data_ary['forum_id'], $data_ary['topic_id'], time());
2197   
2198      //
2199      if ($config['load_db_lastread'] && $user->data['is_registered'])
2200      {
2201          $sql = 'SELECT mark_time
2202              FROM ' . FORUMS_TRACK_TABLE . '
2203              WHERE user_id = ' . $user->data['user_id'] . '
2204                  AND forum_id = ' . $data_ary['forum_id'];
2205          $result = $db->sql_query($sql);
2206          $f_mark_time = (int) $db->sql_fetchfield('mark_time');
2207          $db->sql_freeresult($result);
2208      }
2209      else if ($config['load_anon_lastread'] || $user->data['is_registered'])
2210      {
2211          $f_mark_time = false;
2212      }
2213   
2214      if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered'])
2215      {
2216          // Update forum info
2217          $sql = 'SELECT forum_last_post_time
2218              FROM ' . FORUMS_TABLE . '
2219              WHERE forum_id = ' . $data_ary['forum_id'];
2220          $result = $db->sql_query($sql);
2221          $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time');
2222          $db->sql_freeresult($result);
2223   
2224          update_forum_tracking_info($data_ary['forum_id'], $forum_last_post_time, $f_mark_time, false);
2225      }
2226   
2227      // If a username was supplied or the poster is a guest, we will use the supplied username.
2228      // Doing it this way we can use "...post by guest-username..." in notifications when
2229      // "guest-username" is supplied or ommit the username if it is not.
2230      $username = ($username !== '' || !$user->data['is_registered']) ? $username : $user->data['username'];
2231   
2232      // Send Notifications
2233      $notification_data = array_merge($data_ary, array(
2234          'topic_title'        => (isset($data_ary['topic_title'])) ? $data_ary['topic_title'] : $subject,
2235          'post_username'        => $username,
2236          'poster_id'            => $poster_id,
2237          'post_text'            => $data_ary['message'],
2238          'post_time'            => $current_time,
2239          'post_subject'        => $subject,
2240      ));
2241   
2242      /* @var $phpbb_notifications \phpbb\notification\manager */
2243      $phpbb_notifications = $phpbb_container->get('notification_manager');
2244   
2245      if ($post_visibility == ITEM_APPROVED)
2246      {
2247          switch ($mode)
2248          {
2249              case 'post':
2250                  $phpbb_notifications->add_notifications(array(
2251                      'notification.type.quote',
2252                      'notification.type.topic',
2253                  ), $notification_data);
2254              break;
2255   
2256              case 'reply':
2257              case 'quote':
2258                  $phpbb_notifications->add_notifications(array(
2259                      'notification.type.quote',
2260                      'notification.type.bookmark',
2261                      'notification.type.post',
2262                  ), $notification_data);
2263              break;
2264   
2265              case 'edit_topic':
2266              case 'edit_first_post':
2267              case 'edit':
2268              case 'edit_last_post':
2269                  $phpbb_notifications->update_notifications(array(
2270                      'notification.type.quote',
2271                      'notification.type.bookmark',
2272                      'notification.type.topic',
2273                      'notification.type.post',
2274                  ), $notification_data);
2275              break;
2276          }
2277      }
2278      else if ($post_visibility == ITEM_UNAPPROVED)
2279      {
2280          switch ($mode)
2281          {
2282              case 'post':
2283                  $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data);
2284              break;
2285   
2286              case 'reply':
2287              case 'quote':
2288                  $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data);
2289              break;
2290   
2291              case 'edit_topic':
2292              case 'edit_first_post':
2293              case 'edit':
2294              case 'edit_last_post':
2295                  // Nothing to do here
2296              break;
2297          }
2298      }
2299      else if ($post_visibility == ITEM_REAPPROVE)
2300      {
2301          switch ($mode)
2302          {
2303              case 'edit_topic':
2304              case 'edit_first_post':
2305                  $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data);
2306   
2307                  // Delete the approve_post notification so we can notify the user again,
2308                  // when his post got reapproved
2309                  $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']);
2310              break;
2311   
2312              case 'edit':
2313              case 'edit_last_post':
2314                  $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data);
2315   
2316                  // Delete the approve_post notification so we can notify the user again,
2317                  // when his post got reapproved
2318                  $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']);
2319              break;
2320   
2321              case 'post':
2322              case 'reply':
2323              case 'quote':
2324                  // Nothing to do here
2325              break;
2326          }
2327      }
2328      else if ($post_visibility == ITEM_DELETED)
2329      {
2330          switch ($mode)
2331          {
2332              case 'post':
2333              case 'reply':
2334              case 'quote':
2335              case 'edit_topic':
2336              case 'edit_first_post':
2337              case 'edit':
2338              case 'edit_last_post':
2339                  // Nothing to do here
2340              break;
2341          }
2342      }
2343   
2344      $params = $add_anchor = '';
2345   
2346      if ($post_visibility == ITEM_APPROVED ||
2347          ($auth->acl_get('m_softdelete', $data_ary['forum_id']) && $post_visibility == ITEM_DELETED) ||
2348          ($auth->acl_get('m_approve', $data_ary['forum_id']) && in_array($post_visibility, array(ITEM_UNAPPROVED, ITEM_REAPPROVE))))
2349      {
2350          $params .= '&amp;t=' . $data_ary['topic_id'];
2351   
2352          if ($mode != 'post')
2353          {
2354              $params .= '&amp;p=' . $data_ary['post_id'];
2355              $add_anchor = '#p' . $data_ary['post_id'];
2356          }
2357      }
2358      else if ($mode != 'post' && $post_mode != 'edit_first_post' && $post_mode != 'edit_topic')
2359      {
2360          $params .= '&amp;t=' . $data_ary['topic_id'];
2361      }
2362   
2363      $url = (!$params) ? "{$phpbb_root_path}viewforum.$phpEx" : "{$phpbb_root_path}viewtopic.$phpEx";
2364      $url = append_sid($url, 'f=' . $data_ary['forum_id'] . $params) . $add_anchor;
2365   
2366      $poll = $poll_ary;
2367      $data = $data_ary;
2368      /**
2369      * This event is used for performing actions directly after a post or topic
2370      * has been submitted. When a new topic is posted, the topic ID is
2371      * available in the $data array.
2372      *
2373      * The only action that can be done by altering data made available to this
2374      * event is to modify the return URL ($url).
2375      *
2376      * @event core.submit_post_end
2377      * @var    string    mode                Variable containing posting mode value
2378      * @var    string    subject                Variable containing post subject value
2379      * @var    string    username            Variable containing post author name
2380      * @var    int        topic_type            Variable containing topic type value
2381      * @var    array    poll                Array with the poll data for the post
2382      * @var    array    data                Array with the data for the post
2383      * @var    int        post_visibility        Variable containing up to date post visibility
2384      * @var    bool    update_message        Flag indicating if the post will be updated
2385      * @var    bool    update_search_index    Flag indicating if the search index will be updated
2386      * @var    string    url                    The "Return to topic" URL
2387      *
2388      * @since 3.1.0-a3
2389      * @change 3.1.0-RC3 Added vars mode, subject, username, topic_type,
2390      *        poll, update_message, update_search_index
2391      */
2392      $vars = array(
2393          'mode',
2394          'subject',
2395          'username',
2396          'topic_type',
2397          'poll',
2398          'data',
2399          'post_visibility',
2400          'update_message',
2401          'update_search_index',
2402          'url',
2403      );
2404      extract($phpbb_dispatcher->trigger_event('core.submit_post_end', compact($vars)));
2405      $data_ary = $data;
2406      $poll_ary = $poll;
2407      unset($data);
2408      unset($poll);
2409   
2410      return $url;
2411  }
2412   
2413  /**
2414  * Handle topic bumping
2415  * @param int $forum_id The ID of the forum the topic is being bumped belongs to
2416  * @param int $topic_id The ID of the topic is being bumping
2417  * @param array $post_data Passes some topic parameters:
2418  *                - 'topic_title'
2419  *                - 'topic_last_post_id'
2420  *                - 'topic_last_poster_id'
2421  *                - 'topic_last_post_subject'
2422  *                - 'topic_last_poster_name'
2423  *                - 'topic_last_poster_colour'
2424  * @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time().
2425  * @return string An URL to the bumped topic, example: ./viewtopic.php?forum_id=1&amptopic_id=2&ampp=3#p3
2426  */
2427  function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false)
2428  {
2429      global $config, $db, $user, $phpEx, $phpbb_root_path, $phpbb_log;
2430   
2431      if ($bump_time === false)
2432      {
2433          $bump_time = time();
2434      }
2435   
2436      // Begin bumping
2437      $db->sql_transaction('begin');
2438   
2439      // Update the topic's last post post_time
2440      $sql = 'UPDATE ' . POSTS_TABLE . "
2441          SET post_time = $bump_time
2442          WHERE post_id = {$post_data['topic_last_post_id']}
2443              AND topic_id = $topic_id";
2444      $db->sql_query($sql);
2445   
2446      // Sync the topic's last post time, the rest of the topic's last post data isn't changed
2447      $sql = 'UPDATE ' . TOPICS_TABLE . "
2448          SET topic_last_post_time = $bump_time,
2449              topic_bumped = 1,
2450              topic_bumper = " . $user->data['user_id'] . "
2451          WHERE topic_id = $topic_id";
2452      $db->sql_query($sql);
2453   
2454      // Update the forum's last post info
2455      $sql = 'UPDATE ' . FORUMS_TABLE . "
2456          SET forum_last_post_id = " . $post_data['topic_last_post_id'] . ",
2457              forum_last_poster_id = " . $post_data['topic_last_poster_id'] . ",
2458              forum_last_post_subject = '" . $db->sql_escape($post_data['topic_last_post_subject']) . "',
2459              forum_last_post_time = $bump_time,
2460              forum_last_poster_name = '" . $db->sql_escape($post_data['topic_last_poster_name']) . "',
2461              forum_last_poster_colour = '" . $db->sql_escape($post_data['topic_last_poster_colour']) . "'
2462          WHERE forum_id = $forum_id";
2463      $db->sql_query($sql);
2464   
2465      // Update bumper's time of the last posting to prevent flood
2466      $sql = 'UPDATE ' . USERS_TABLE . "
2467          SET user_lastpost_time = $bump_time
2468          WHERE user_id = " . $user->data['user_id'];
2469      $db->sql_query($sql);
2470   
2471      $db->sql_transaction('commit');
2472   
2473      // Mark this topic as posted to
2474      markread('post', $forum_id, $topic_id, $bump_time);
2475   
2476      // Mark this topic as read
2477      markread('topic', $forum_id, $topic_id, $bump_time);
2478   
2479      // Update forum tracking info
2480      if ($config['load_db_lastread'] && $user->data['is_registered'])
2481      {
2482          $sql = 'SELECT mark_time
2483              FROM ' . FORUMS_TRACK_TABLE . '
2484              WHERE user_id = ' . $user->data['user_id'] . '
2485                  AND forum_id = ' . $forum_id;
2486          $result = $db->sql_query($sql);
2487          $f_mark_time = (int) $db->sql_fetchfield('mark_time');
2488          $db->sql_freeresult($result);
2489      }
2490      else if ($config['load_anon_lastread'] || $user->data['is_registered'])
2491      {
2492          $f_mark_time = false;
2493      }
2494   
2495      if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered'])
2496      {
2497          // Update forum info
2498          $sql = 'SELECT forum_last_post_time
2499              FROM ' . FORUMS_TABLE . '
2500              WHERE forum_id = ' . $forum_id;
2501          $result = $db->sql_query($sql);
2502          $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time');
2503          $db->sql_freeresult($result);
2504   
2505          update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time, false);
2506      }
2507   
2508      $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_BUMP_TOPIC', false, array(
2509          'forum_id' => $forum_id,
2510          'topic_id' => $topic_id,
2511          $post_data['topic_title']
2512      ));
2513   
2514      $url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;p={$post_data['topic_last_post_id']}") . "#p{$post_data['topic_last_post_id']}";
2515   
2516      return $url;
2517  }
2518   
2519  /**
2520  * Show upload popup (progress bar)
2521  */
2522  function phpbb_upload_popup($forum_style = 0)
2523  {
2524      global $template, $user;
2525   
2526      ($forum_style) ? $user->setup('posting', $forum_style) : $user->setup('posting');
2527   
2528      page_header($user->lang['PROGRESS_BAR']);
2529   
2530      $template->set_filenames(array(
2531              'popup'    => 'posting_progress_bar.html')
2532      );
2533   
2534      $template->assign_vars(array(
2535              'PROGRESS_BAR'    => $user->img('upload_bar', $user->lang['UPLOAD_IN_PROGRESS']))
2536      );
2537   
2538      $template->display('popup');
2539   
2540      garbage_collection();
2541      exit_handler();
2542  }
2543   
2544  /**
2545  * Do the various checks required for removing posts as well as removing it
2546  */
2547  function phpbb_handle_post_delete($forum_id, $topic_id, $post_id, &$post_data, $is_soft = false, $delete_reason = '')
2548  {
2549      global $user, $auth, $config, $request;
2550      global $phpbb_root_path, $phpEx, $phpbb_log;
2551   
2552      $perm_check = ($is_soft) ? 'softdelete' : 'delete';
2553   
2554      // If moderator removing post or user itself removing post, present a confirmation screen
2555      if ($auth->acl_get("m_$perm_check", $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get("f_$perm_check", $forum_id) && $post_id == $post_data['topic_last_post_id'] && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time'])))
2556      {
2557          $s_hidden_fields = array(
2558              'p'        => $post_id,
2559              'f'        => $forum_id,
2560              'mode'    => ($is_soft) ? 'soft_delete' : 'delete',
2561          );
2562   
2563          if (confirm_box(true))
2564          {
2565              $data = array(
2566                  'topic_first_post_id'    => $post_data['topic_first_post_id'],
2567                  'topic_last_post_id'    => $post_data['topic_last_post_id'],
2568                  'topic_posts_approved'        => $post_data['topic_posts_approved'],
2569                  'topic_posts_unapproved'    => $post_data['topic_posts_unapproved'],
2570                  'topic_posts_softdeleted'    => $post_data['topic_posts_softdeleted'],
2571                  'topic_visibility'        => $post_data['topic_visibility'],
2572                  'topic_type'            => $post_data['topic_type'],
2573                  'post_visibility'        => $post_data['post_visibility'],
2574                  'post_reported'            => $post_data['post_reported'],
2575                  'post_time'                => $post_data['post_time'],
2576                  'poster_id'                => $post_data['poster_id'],
2577                  'post_postcount'        => $post_data['post_postcount'],
2578              );
2579   
2580              $next_post_id = delete_post($forum_id, $topic_id, $post_id, $data, $is_soft, $delete_reason);
2581              $post_username = ($post_data['poster_id'] == ANONYMOUS && !empty($post_data['post_username'])) ? $post_data['post_username'] : $post_data['username'];
2582   
2583              if ($next_post_id === false)
2584              {
2585                  $phpbb_log->add('mod', $user->data['user_id'], $user->ip, (($is_soft) ? 'LOG_SOFTDELETE_TOPIC' : 'LOG_DELETE_TOPIC'), false, array(
2586                      'forum_id' => $forum_id,
2587                      'topic_id' => $topic_id,
2588                      $post_data['topic_title'],
2589                      $post_username,
2590                      $delete_reason
2591                  ));
2592   
2593                  $meta_info = append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id");
2594                  $message = $user->lang['POST_DELETED'];
2595              }
2596              else
2597              {
2598                  $phpbb_log->add('mod', $user->data['user_id'], $user->ip, (($is_soft) ? 'LOG_SOFTDELETE_POST' : 'LOG_DELETE_POST'), false, array(
2599                      'forum_id' => $forum_id,
2600                      'topic_id' => $topic_id,
2601                      'post_id'  => $post_id,
2602                      $post_data['post_subject'],
2603                      $post_username,
2604                      $delete_reason
2605                  ));
2606   
2607                  $meta_info = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;p=$next_post_id") . "#p$next_post_id";
2608                  $message = $user->lang['POST_DELETED'];
2609   
2610                  if (!$request->is_ajax())
2611                  {
2612                      $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $meta_info . '">', '</a>');
2613                  }
2614              }
2615   
2616              meta_refresh(3, $meta_info);
2617              if (!$request->is_ajax())
2618              {
2619                  $message .= '<br /><br />' . $user->lang('RETURN_FORUM', '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) . '">', '</a>');
2620              }
2621              trigger_error($message);
2622          }
2623          else
2624          {
2625              global $user, $template, $request;
2626   
2627              $can_delete = $auth->acl_get('m_delete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_delete', $forum_id));
2628              $can_softdelete = $auth->acl_get('m_softdelete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_softdelete', $forum_id));
2629   
2630              $template->assign_vars(array(
2631                  'S_SOFTDELETED'            => $post_data['post_visibility'] == ITEM_DELETED,
2632                  'S_CHECKED_PERMANENT'    => $request->is_set_post('delete_permanent') ? ' checked="checked"' : '',
2633                  'S_ALLOWED_DELETE'        => $can_delete,
2634                  'S_ALLOWED_SOFTDELETE'    => $can_softdelete,
2635              ));
2636   
2637              $l_confirm = 'DELETE_POST';
2638              if ($post_data['post_visibility'] == ITEM_DELETED)
2639              {
2640                  $l_confirm .= '_PERMANENTLY';
2641                  $s_hidden_fields['delete_permanent'] = '1';
2642              }
2643              else if (!$can_softdelete)
2644              {
2645                  $s_hidden_fields['delete_permanent'] = '1';
2646              }
2647   
2648              confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html');
2649          }
2650      }
2651   
2652      // If we are here the user is not able to delete - present the correct error message
2653      if ($post_data['poster_id'] != $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id))
2654      {
2655          trigger_error('DELETE_OWN_POSTS');
2656      }
2657   
2658      if ($post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id) && $post_id != $post_data['topic_last_post_id'])
2659      {
2660          trigger_error('CANNOT_DELETE_REPLIED');
2661      }
2662   
2663      trigger_error('USER_CANNOT_DELETE');
2664  }
2665