Verzeichnisstruktur phpBB-3.0.0


Veröffentlicht
12.12.2007

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_admin.php

Zuletzt modifiziert: 09.10.2024, 12:50 - Dateigröße: 79.34 KiB


 0001  <?php
 0002  /**
 0003  *
 0004  * @package acp
 0005  * @version $Id$
 0006  * @copyright (c) 2005 phpBB Group
 0007  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 0008  *
 0009  */
 0010   
 0011  /**
 0012  * @ignore
 0013  */
 0014  if (!defined('IN_PHPBB'))
 0015  {
 0016      exit;
 0017  }
 0018   
 0019  /**
 0020  * Recalculate Binary Tree
 0021  function recalc_btree($sql_id, $sql_table, $module_class = '')
 0022  {
 0023      global $db;
 0024   
 0025      if (!$sql_id || !$sql_table)
 0026      {
 0027          return;
 0028      }
 0029   
 0030      $sql_where = ($module_class) ? " WHERE module_class = '" . $db->sql_escape($module_class) . "'" : '';
 0031   
 0032      // Reset to minimum possible left and right id
 0033      $sql = "SELECT MIN(left_id) as min_left_id, MIN(right_id) as min_right_id
 0034          FROM $sql_table
 0035          $sql_where";
 0036      $result = $db->sql_query($sql);
 0037      $row = $db->sql_fetchrow($result);
 0038      $db->sql_freeresult($result);
 0039   
 0040      $substract = (int) (min($row['min_left_id'], $row['min_right_id']) - 1);
 0041   
 0042      if ($substract > 0)
 0043      {
 0044          $sql = "UPDATE $sql_table
 0045              SET left_id = left_id - $substract, right_id = right_id - $substract
 0046              $sql_where";
 0047          $db->sql_query($sql);
 0048      }
 0049   
 0050      $sql = "SELECT $sql_id, parent_id, left_id, right_id
 0051          FROM $sql_table
 0052          $sql_where
 0053          ORDER BY left_id ASC, parent_id ASC, $sql_id ASC";
 0054      $f_result = $db->sql_query($sql);
 0055   
 0056      while ($item_data = $db->sql_fetchrow($f_result))
 0057      {
 0058          if ($item_data['parent_id'])
 0059          {
 0060              $sql = "SELECT left_id, right_id
 0061                  FROM $sql_table
 0062                  $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . "
 0063                      $sql_id = {$item_data['parent_id']}";
 0064              $result = $db->sql_query($sql);
 0065   
 0066              if (!$row = $db->sql_fetchrow($result))
 0067              {
 0068                  $sql = "UPDATE $sql_table SET parent_id = 0 WHERE $sql_id = " . $item_data[$sql_id];
 0069                  $db->sql_query($sql);
 0070              }
 0071              $db->sql_freeresult($result);
 0072   
 0073              $sql = "UPDATE $sql_table
 0074                  SET left_id = left_id + 2, right_id = right_id + 2
 0075                  $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . "
 0076                      left_id > {$row['right_id']}";
 0077              $db->sql_query($sql);
 0078   
 0079              $sql = "UPDATE $sql_table
 0080                  SET right_id = right_id + 2
 0081                  $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . "
 0082                      {$row['left_id']} BETWEEN left_id AND right_id";
 0083              $db->sql_query($sql);
 0084   
 0085              $item_data['left_id'] = $row['right_id'];
 0086              $item_data['right_id'] = $row['right_id'] + 1;
 0087          }
 0088          else
 0089          {
 0090              $sql = "SELECT MAX(right_id) AS right_id
 0091                  FROM $sql_table
 0092                  $sql_where";
 0093              $result = $db->sql_query($sql);
 0094              $row = $db->sql_fetchrow($result);
 0095              $db->sql_freeresult($result);
 0096   
 0097              $item_data['left_id'] = $row['right_id'] + 1;
 0098              $item_data['right_id'] = $row['right_id'] + 2;
 0099          }
 0100      
 0101          $sql = "UPDATE $sql_table
 0102              SET left_id = {$item_data['left_id']}, right_id = {$item_data['right_id']}
 0103              WHERE $sql_id = " . $item_data[$sql_id];
 0104          $db->sql_query($sql);
 0105      }
 0106      $db->sql_freeresult($f_result);
 0107  }
 0108  */
 0109   
 0110  /**
 0111  * Simple version of jumpbox, just lists authed forums
 0112  */
 0113  function make_forum_select($select_id = false, $ignore_id = false, $ignore_acl = false, $ignore_nonpost = false, $ignore_emptycat = true, $only_acl_post = false, $return_array = false)
 0114  {
 0115      global $db, $user, $auth;
 0116   
 0117      $acl = ($ignore_acl) ? '' : (($only_acl_post) ? 'f_post' : array('f_list', 'a_forum', 'a_forumadd', 'a_forumdel'));
 0118   
 0119      // This query is identical to the jumpbox one
 0120      $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id
 0121          FROM ' . FORUMS_TABLE . '
 0122          ORDER BY left_id ASC';
 0123      $result = $db->sql_query($sql, 600);
 0124   
 0125      $right = 0;
 0126      $padding_store = array('0' => '');
 0127      $padding = '';
 0128      $forum_list = ($return_array) ? array() : '';
 0129   
 0130      // Sometimes it could happen that forums will be displayed here not be displayed within the index page
 0131      // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions.
 0132      // If this happens, the padding could be "broken"
 0133   
 0134      while ($row = $db->sql_fetchrow($result))
 0135      {
 0136          if ($row['left_id'] < $right)
 0137          {
 0138              $padding .= '&nbsp; &nbsp;';
 0139              $padding_store[$row['parent_id']] = $padding;
 0140          }
 0141          else if ($row['left_id'] > $right + 1)
 0142          {
 0143              $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : '';
 0144          }
 0145   
 0146          $right = $row['right_id'];
 0147          $disabled = false;
 0148   
 0149          if ($acl && !$auth->acl_gets($acl, $row['forum_id']))
 0150          {
 0151              // List permission?
 0152              if ($auth->acl_get('f_list', $row['forum_id']))
 0153              {
 0154                  $disabled = true;
 0155              }
 0156              else
 0157              {
 0158                  continue;
 0159              }
 0160          }
 0161   
 0162          if (
 0163              ((is_array($ignore_id) && in_array($row['forum_id'], $ignore_id)) || $row['forum_id'] == $ignore_id)
 0164              ||
 0165              // Non-postable forum with no subforums, don't display
 0166              ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']) && $ignore_emptycat)
 0167              ||
 0168              ($row['forum_type'] != FORUM_POST && $ignore_nonpost)
 0169              )
 0170          {
 0171              $disabled = true;
 0172          }
 0173   
 0174          if ($return_array)
 0175          {
 0176              // Include some more information...
 0177              $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? true : false) : (($row['forum_id'] == $select_id) ? true : false);
 0178              $forum_list[$row['forum_id']] = array_merge(array('padding' => $padding, 'selected' => ($selected && !$disabled), 'disabled' => $disabled), $row);
 0179          }
 0180          else
 0181          {
 0182              $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? ' selected="selected"' : '') : (($row['forum_id'] == $select_id) ? ' selected="selected"' : '');
 0183              $forum_list .= '<option value="' . $row['forum_id'] . '"' . (($disabled) ? ' disabled="disabled" class="disabled-option"' : $selected) . '>' . $padding . $row['forum_name'] . '</option>';
 0184          }
 0185      }
 0186      $db->sql_freeresult($result);
 0187      unset($padding_store);
 0188   
 0189      return $forum_list;
 0190  }
 0191   
 0192  /**
 0193  * Generate size select options
 0194  */
 0195  function size_select_options($size_compare)
 0196  {
 0197      global $user;
 0198   
 0199      $size_types_text = array($user->lang['BYTES'], $user->lang['KB'], $user->lang['MB']);
 0200      $size_types = array('b', 'kb', 'mb');
 0201   
 0202      $s_size_options = '';
 0203   
 0204      for ($i = 0, $size = sizeof($size_types_text); $i < $size; $i++)
 0205      {
 0206          $selected = ($size_compare == $size_types[$i]) ? ' selected="selected"' : '';
 0207          $s_size_options .= '<option value="' . $size_types[$i] . '"' . $selected . '>' . $size_types_text[$i] . '</option>';
 0208      }
 0209   
 0210      return $s_size_options;
 0211  }
 0212   
 0213  /**
 0214  * Generate list of groups (option fields without select)
 0215  *
 0216  * @param int $group_id The default group id to mark as selected
 0217  * @param array $exclude_ids The group ids to exclude from the list, false (default) if you whish to exclude no id
 0218  * @param int $manage_founder If set to false (default) all groups are returned, if 0 only those groups returned not being managed by founders only, if 1 only those groups returned managed by founders only.
 0219  *
 0220  * @return string The list of options.
 0221  */
 0222  function group_select_options($group_id, $exclude_ids = false, $manage_founder = false)
 0223  {
 0224      global $db, $user, $config;
 0225   
 0226      $exclude_sql = ($exclude_ids !== false && sizeof($exclude_ids)) ? 'WHERE ' . $db->sql_in_set('group_id', array_map('intval', $exclude_ids), true) : '';
 0227      $sql_and = (!$config['coppa_enable']) ? (($exclude_sql) ? ' AND ' : ' WHERE ') . "group_name <> 'REGISTERED_COPPA'" : '';
 0228      $sql_founder = ($manage_founder !== false) ? (($exclude_sql || $sql_and) ? ' AND ' : ' WHERE ') . 'group_founder_manage = ' . (int) $manage_founder : '';
 0229   
 0230      $sql = 'SELECT group_id, group_name, group_type
 0231          FROM ' . GROUPS_TABLE . "
 0232          $exclude_sql
 0233          $sql_and
 0234          $sql_founder
 0235          ORDER BY group_type DESC, group_name ASC";
 0236      $result = $db->sql_query($sql);
 0237   
 0238      $s_group_options = '';
 0239      while ($row = $db->sql_fetchrow($result))
 0240      {
 0241          $selected = ($row['group_id'] == $group_id) ? ' selected="selected"' : '';
 0242          $s_group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '"' . $selected . '>' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>';
 0243      }
 0244      $db->sql_freeresult($result);
 0245   
 0246      return $s_group_options;
 0247  }
 0248   
 0249  /**
 0250  * Obtain authed forums list
 0251  */
 0252  function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only = false, $no_cache = false)
 0253  {
 0254      global $db, $auth;
 0255      static $forum_rows;
 0256   
 0257      if (!isset($forum_rows))
 0258      {
 0259          // This query is identical to the jumpbox one
 0260          $expire_time = ($no_cache) ? 0 : 600;
 0261   
 0262          $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id
 0263              FROM ' . FORUMS_TABLE . '
 0264              ORDER BY left_id ASC';
 0265          $result = $db->sql_query($sql, $expire_time);
 0266   
 0267          $forum_rows = array();
 0268   
 0269          $right = $padding = 0;
 0270          $padding_store = array('0' => 0);
 0271   
 0272          while ($row = $db->sql_fetchrow($result))
 0273          {
 0274              if ($row['left_id'] < $right)
 0275              {
 0276                  $padding++;
 0277                  $padding_store[$row['parent_id']] = $padding;
 0278              }
 0279              else if ($row['left_id'] > $right + 1)
 0280              {
 0281                  // Ok, if the $padding_store for this parent is empty there is something wrong. For now we will skip over it.
 0282                  // @todo digging deep to find out "how" this can happen.
 0283                  $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding;
 0284              }
 0285   
 0286              $right = $row['right_id'];
 0287              $row['padding'] = $padding;
 0288   
 0289              $forum_rows[] = $row;
 0290          }
 0291          $db->sql_freeresult($result);
 0292          unset($padding_store);
 0293      }
 0294   
 0295      $rowset = array();
 0296      foreach ($forum_rows as $row)
 0297      {
 0298          if ($postable_only && $row['forum_type'] != FORUM_POST)
 0299          {
 0300              continue;
 0301          }
 0302   
 0303          if ($acl_list == '' || ($acl_list != '' && $auth->acl_gets($acl_list, $row['forum_id'])))
 0304          {
 0305              $rowset[] = ($id_only) ? $row['forum_id'] : $row;
 0306          }
 0307      }
 0308   
 0309      return $rowset;
 0310  }
 0311   
 0312  /**
 0313  * Get forum branch
 0314  */
 0315  function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $include_forum = true)
 0316  {
 0317      global $db;
 0318   
 0319      switch ($type)
 0320      {
 0321          case 'parents':
 0322              $condition = 'f1.left_id BETWEEN f2.left_id AND f2.right_id';
 0323          break;
 0324   
 0325          case 'children':
 0326              $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id';
 0327          break;
 0328   
 0329          default:
 0330              $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id OR f1.left_id BETWEEN f2.left_id AND f2.right_id';
 0331          break;
 0332      }
 0333   
 0334      $rows = array();
 0335   
 0336      $sql = 'SELECT f2.*
 0337          FROM ' . FORUMS_TABLE . ' f1
 0338          LEFT JOIN ' . FORUMS_TABLE . " f2 ON ($condition)
 0339          WHERE f1.forum_id = $forum_id
 0340          ORDER BY f2.left_id " . (($order == 'descending') ? 'ASC' : 'DESC');
 0341      $result = $db->sql_query($sql);
 0342   
 0343      while ($row = $db->sql_fetchrow($result))
 0344      {
 0345          if (!$include_forum && $row['forum_id'] == $forum_id)
 0346          {
 0347              continue;
 0348          }
 0349   
 0350          $rows[] = $row;
 0351      }
 0352      $db->sql_freeresult($result);
 0353   
 0354      return $rows;
 0355  }
 0356   
 0357  /**
 0358  * Get physical file listing
 0359  */
 0360  function filelist($rootdir, $dir = '', $type = 'gif|jpg|jpeg|png')
 0361  {
 0362      $matches = array();
 0363   
 0364      // Remove initial / if present
 0365      $rootdir = (substr($rootdir, 0, 1) == '/') ? substr($rootdir, 1) : $rootdir;
 0366      // Add closing / if not present
 0367      $rootdir = ($rootdir && substr($rootdir, -1) != '/') ? $rootdir . '/' : $rootdir;
 0368   
 0369      // Remove initial / if present
 0370      $dir = (substr($dir, 0, 1) == '/') ? substr($dir, 1) : $dir;
 0371      // Add closing / if not present
 0372      $dir = ($dir && substr($dir, -1) != '/') ? $dir . '/' : $dir;
 0373   
 0374      if (!is_dir($rootdir . $dir))
 0375      {
 0376          return $matches;
 0377      }
 0378   
 0379      $dh = @opendir($rootdir . $dir);
 0380   
 0381      if (!$dh)
 0382      {
 0383          return $matches;
 0384      }
 0385   
 0386      while (($fname = readdir($dh)) !== false)
 0387      {
 0388          if (is_file("$rootdir$dir$fname"))
 0389          {
 0390              if (filesize("$rootdir$dir$fname") && preg_match('#\.' . $type . '$#i', $fname))
 0391              {
 0392                  $matches[$dir][] = $fname;
 0393              }
 0394          }
 0395          else if ($fname[0] != '.' && is_dir("$rootdir$dir$fname"))
 0396          {
 0397              $matches += filelist($rootdir, "$dir$fname", $type);
 0398          }
 0399      }
 0400      closedir($dh);
 0401   
 0402      return $matches;
 0403  }
 0404   
 0405  /**
 0406  * Move topic(s)
 0407  */
 0408  function move_topics($topic_ids, $forum_id, $auto_sync = true)
 0409  {
 0410      global $db;
 0411   
 0412      if (empty($topic_ids))
 0413      {
 0414          return;
 0415      }
 0416   
 0417      $forum_ids = array($forum_id);
 0418   
 0419      if (!is_array($topic_ids))
 0420      {
 0421          $topic_ids = array($topic_ids);
 0422      }
 0423   
 0424      $sql = 'DELETE FROM ' . TOPICS_TABLE . '
 0425          WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids) . '
 0426              AND forum_id = ' . $forum_id;
 0427      $db->sql_query($sql);
 0428   
 0429      if ($auto_sync)
 0430      {
 0431          $sql = 'SELECT DISTINCT forum_id
 0432              FROM ' . TOPICS_TABLE . '
 0433              WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
 0434          $result = $db->sql_query($sql);
 0435   
 0436          while ($row = $db->sql_fetchrow($result))
 0437          {
 0438              $forum_ids[] = $row['forum_id'];
 0439          }
 0440          $db->sql_freeresult($result);
 0441      }
 0442   
 0443      $table_ary = array(TOPICS_TABLE, POSTS_TABLE, LOG_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE);
 0444      foreach ($table_ary as $table)
 0445      {
 0446          $sql = "UPDATE $table
 0447              SET forum_id = $forum_id
 0448              WHERE " . $db->sql_in_set('topic_id', $topic_ids);
 0449          $db->sql_query($sql);
 0450      }
 0451      unset($table_ary);
 0452   
 0453      if ($auto_sync)
 0454      {
 0455          sync('forum', 'forum_id', $forum_ids, true, true);
 0456          unset($forum_ids);
 0457      }
 0458  }
 0459   
 0460  /**
 0461  * Move post(s)
 0462  */
 0463  function move_posts($post_ids, $topic_id, $auto_sync = true)
 0464  {
 0465      global $db;
 0466   
 0467      if (!is_array($post_ids))
 0468      {
 0469          $post_ids = array($post_ids);
 0470      }
 0471   
 0472      $forum_ids = array();
 0473      $topic_ids = array($topic_id);
 0474   
 0475      $sql = 'SELECT DISTINCT topic_id, forum_id
 0476          FROM ' . POSTS_TABLE . '
 0477          WHERE ' . $db->sql_in_set('post_id', $post_ids);
 0478      $result = $db->sql_query($sql);
 0479   
 0480      while ($row = $db->sql_fetchrow($result))
 0481      {
 0482          $forum_ids[] = $row['forum_id'];
 0483          $topic_ids[] = $row['topic_id'];
 0484      }
 0485      $db->sql_freeresult($result);
 0486   
 0487      $sql = 'SELECT forum_id
 0488          FROM ' . TOPICS_TABLE . '
 0489          WHERE topic_id = ' . $topic_id;
 0490      $result = $db->sql_query($sql);
 0491      $forum_row = $db->sql_fetchrow($result);
 0492      $db->sql_freeresult($result);
 0493   
 0494      if (!$forum_row)
 0495      {
 0496          trigger_error('NO_TOPIC');
 0497      }
 0498   
 0499      $sql = 'UPDATE ' . POSTS_TABLE . '
 0500          SET forum_id = ' . $forum_row['forum_id'] . ", topic_id = $topic_id
 0501          WHERE " . $db->sql_in_set('post_id', $post_ids);
 0502      $db->sql_query($sql);
 0503   
 0504      $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
 0505          SET topic_id = $topic_id, in_message = 0
 0506          WHERE " . $db->sql_in_set('post_msg_id', $post_ids);
 0507      $db->sql_query($sql);
 0508   
 0509      if ($auto_sync)
 0510      {
 0511          $forum_ids[] = $forum_row['forum_id'];
 0512   
 0513          sync('topic_reported', 'topic_id', $topic_ids);
 0514          sync('topic_attachment', 'topic_id', $topic_ids);
 0515          sync('topic', 'topic_id', $topic_ids, true);
 0516          sync('forum', 'forum_id', $forum_ids, true, true);
 0517      }
 0518   
 0519      // Update posted information
 0520      update_posted_info($topic_ids);
 0521  }
 0522   
 0523  /**
 0524  * Remove topic(s)
 0525  */
 0526  function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_sync = true, $call_delete_posts = true)
 0527  {
 0528      global $db, $config;
 0529   
 0530      $approved_topics = 0;
 0531      $forum_ids = $topic_ids = array();
 0532   
 0533      if ($where_type === 'range')
 0534      {
 0535          $where_clause = $where_ids;
 0536      }
 0537      else
 0538      {
 0539          $where_ids = (is_array($where_ids)) ? array_unique($where_ids) : array($where_ids);
 0540   
 0541          if (!sizeof($where_ids))
 0542          {
 0543              return array('topics' => 0, 'posts' => 0);
 0544          }
 0545   
 0546          $where_clause = $db->sql_in_set($where_type, $where_ids);
 0547      }
 0548   
 0549      // Making sure that delete_posts does not call delete_topics again...
 0550      $return = array(
 0551          'posts' => ($call_delete_posts) ? delete_posts($where_type, $where_ids, false, true, $post_count_sync, false) : 0,
 0552      );
 0553   
 0554      $sql = 'SELECT topic_id, forum_id, topic_approved
 0555          FROM ' . TOPICS_TABLE . '
 0556          WHERE ' . $where_clause;
 0557      $result = $db->sql_query($sql);
 0558   
 0559      while ($row = $db->sql_fetchrow($result))
 0560      {
 0561          $forum_ids[] = $row['forum_id'];
 0562          $topic_ids[] = $row['topic_id'];
 0563   
 0564          if ($row['topic_approved'])
 0565          {
 0566              $approved_topics++;
 0567          }
 0568      }
 0569      $db->sql_freeresult($result);
 0570   
 0571      $return['topics'] = sizeof($topic_ids);
 0572   
 0573      if (!sizeof($topic_ids))
 0574      {
 0575          return $return;
 0576      }
 0577   
 0578      $db->sql_transaction('begin');
 0579   
 0580      $table_ary = array(TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, POLL_VOTES_TABLE, POLL_OPTIONS_TABLE, TOPICS_WATCH_TABLE, TOPICS_TABLE);
 0581   
 0582      foreach ($table_ary as $table)
 0583      {
 0584          $sql = "DELETE FROM $table
 0585              WHERE " . $db->sql_in_set('topic_id', $topic_ids);
 0586          $db->sql_query($sql);
 0587      }
 0588      unset($table_ary);
 0589   
 0590      $moved_topic_ids = array();
 0591   
 0592      // update the other forums
 0593      $sql = 'SELECT topic_id, forum_id
 0594          FROM ' . TOPICS_TABLE . '
 0595          WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids);
 0596      $result = $db->sql_query($sql);
 0597   
 0598      while ($row = $db->sql_fetchrow($result))
 0599      {
 0600          $forum_ids[] = $row['forum_id'];
 0601          $moved_topic_ids[] = $row['topic_id'];
 0602      }
 0603      $db->sql_freeresult($result);
 0604   
 0605      if (sizeof($moved_topic_ids))
 0606      {
 0607          $sql = 'DELETE FROM ' . TOPICS_TABLE . '
 0608              WHERE ' . $db->sql_in_set('topic_id', $moved_topic_ids);
 0609          $db->sql_query($sql);
 0610      }
 0611   
 0612      $db->sql_transaction('commit');
 0613   
 0614      if ($auto_sync)
 0615      {
 0616          sync('forum', 'forum_id', array_unique($forum_ids), true, true);
 0617          sync('topic_reported', $where_type, $where_ids);
 0618      }
 0619   
 0620      if ($approved_topics)
 0621      {
 0622          set_config('num_topics', $config['num_topics'] - $approved_topics, true);
 0623      }
 0624   
 0625      return $return;
 0626  }
 0627   
 0628  /**
 0629  * Remove post(s)
 0630  */
 0631  function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = true, $post_count_sync = true, $call_delete_topics = true)
 0632  {
 0633      global $db, $config, $phpbb_root_path, $phpEx;
 0634   
 0635      if ($where_type === 'range')
 0636      {
 0637          $where_clause = $where_ids;
 0638      }
 0639      else
 0640      {
 0641          if (is_array($where_ids))
 0642          {
 0643              $where_ids = array_unique($where_ids);
 0644          }
 0645          else
 0646          {
 0647              $where_ids = array($where_ids);
 0648          }
 0649   
 0650          if (!sizeof($where_ids))
 0651          {
 0652              return false;
 0653          }
 0654   
 0655          $where_clause = $db->sql_in_set($where_type, array_map('intval', $where_ids));
 0656      }
 0657   
 0658      $approved_posts = 0;
 0659      $post_ids = $topic_ids = $forum_ids = $post_counts = $remove_topics = array();
 0660   
 0661      $sql = 'SELECT post_id, poster_id, post_approved, post_postcount, topic_id, forum_id
 0662          FROM ' . POSTS_TABLE . '
 0663          WHERE ' . $where_clause;
 0664      $result = $db->sql_query($sql);
 0665   
 0666      while ($row = $db->sql_fetchrow($result))
 0667      {
 0668          $post_ids[] = $row['post_id'];
 0669          $poster_ids[] = $row['poster_id'];
 0670          $topic_ids[] = $row['topic_id'];
 0671          $forum_ids[] = $row['forum_id'];
 0672   
 0673          if ($row['post_postcount'] && $post_count_sync)
 0674          {
 0675              $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1;
 0676          }
 0677   
 0678          if ($row['post_approved'])
 0679          {
 0680              $approved_posts++;
 0681          }
 0682      }
 0683      $db->sql_freeresult($result);
 0684   
 0685      if (!sizeof($post_ids))
 0686      {
 0687          return false;
 0688      }
 0689   
 0690      $db->sql_transaction('begin');
 0691   
 0692      $table_ary = array(POSTS_TABLE, REPORTS_TABLE);
 0693   
 0694      foreach ($table_ary as $table)
 0695      {
 0696          $sql = "DELETE FROM $table
 0697              WHERE " . $db->sql_in_set('post_id', $post_ids);
 0698          $db->sql_query($sql);
 0699      }
 0700      unset($table_ary);
 0701   
 0702      // Adjust users post counts
 0703      if (sizeof($post_counts) && $post_count_sync)
 0704      {
 0705          foreach ($post_counts as $poster_id => $substract)
 0706          {
 0707              $sql = 'UPDATE ' . USERS_TABLE . '
 0708                  SET user_posts = 0
 0709                  WHERE user_id = ' . $poster_id . '
 0710                  AND user_posts < ' . $substract;
 0711              $db->sql_query($sql);
 0712              $sql = 'UPDATE ' . USERS_TABLE . '
 0713                  SET user_posts = user_posts - ' . $substract . '
 0714                  WHERE user_id = ' . $poster_id . '
 0715                  AND user_posts >= ' . $substract;
 0716              $db->sql_query($sql);
 0717          }
 0718      }
 0719   
 0720      // Remove topics now having no posts?
 0721      if (sizeof($topic_ids))
 0722      {
 0723          $sql = 'SELECT topic_id
 0724              FROM ' . POSTS_TABLE . '
 0725              WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
 0726              GROUP BY topic_id';
 0727          $result = $db->sql_query($sql);
 0728   
 0729          while ($row = $db->sql_fetchrow($result))
 0730          {
 0731              $remove_topics[] = $row['topic_id'];
 0732          }
 0733          $db->sql_freeresult($result);
 0734   
 0735          // Actually, those not within remove_topics should be removed. ;)
 0736          $remove_topics = array_diff($topic_ids, $remove_topics);
 0737      }
 0738   
 0739      // Remove the message from the search index
 0740      $search_type = basename($config['search_type']);
 0741   
 0742      if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx))
 0743      {
 0744          trigger_error('NO_SUCH_SEARCH_MODULE');
 0745      }
 0746   
 0747      include_once("{$phpbb_root_path}includes/search/$search_type.$phpEx");
 0748   
 0749      $error = false;
 0750      $search = new $search_type($error);
 0751   
 0752      if ($error)
 0753      {
 0754          trigger_error($error);
 0755      }
 0756   
 0757      $search->index_remove($post_ids, $poster_ids, $forum_ids);
 0758   
 0759      delete_attachments('post', $post_ids, false);
 0760   
 0761      $db->sql_transaction('commit');
 0762   
 0763      // Resync topics_posted table
 0764      if ($posted_sync)
 0765      {
 0766          update_posted_info($topic_ids);
 0767      }
 0768   
 0769      if ($auto_sync)
 0770      {
 0771          sync('topic_reported', 'topic_id', $topic_ids);
 0772          sync('topic', 'topic_id', $topic_ids, true);
 0773          sync('forum', 'forum_id', $forum_ids, true, true);
 0774      }
 0775   
 0776      if ($approved_posts)
 0777      {
 0778          set_config('num_posts', $config['num_posts'] - $approved_posts, true);
 0779      }
 0780   
 0781      // We actually remove topics now to not be inconsistent (the delete_topics function calls this function too)
 0782      if (sizeof($remove_topics) && $call_delete_topics)
 0783      {
 0784          delete_topics('topic_id', $remove_topics, $auto_sync, $post_count_sync, false);
 0785      }
 0786   
 0787      return sizeof($post_ids);
 0788  }
 0789   
 0790  /**
 0791  * Delete Attachments
 0792  *
 0793  * @param string $mode can be: post|topic|attach|user
 0794  * @param mixed $ids can be: post_ids, topic_ids, attach_ids, user_ids
 0795  * @param bool $resync set this to false if you are deleting posts or topics
 0796  */
 0797  function delete_attachments($mode, $ids, $resync = true)
 0798  {
 0799      global $db, $config;
 0800   
 0801      if (is_array($ids) && sizeof($ids))
 0802      {
 0803          $ids = array_unique($ids);
 0804          $ids = array_map('intval', $ids);
 0805      }
 0806      else
 0807      {
 0808          $ids = array((int) $ids);
 0809      }
 0810   
 0811      if (!sizeof($ids))
 0812      {
 0813          return false;
 0814      }
 0815   
 0816      $sql_id = ($mode == 'user') ? 'poster_id' : (($mode == 'post') ? 'post_msg_id' : (($mode == 'topic') ? 'topic_id' : 'attach_id'));
 0817   
 0818      $post_ids = $topic_ids = $physical = array();
 0819   
 0820      // Collect post and topics ids for later use
 0821      if ($mode == 'attach' || $mode == 'user' || ($mode == 'topic' && $resync))
 0822      {
 0823          $sql = 'SELECT post_msg_id as post_id, topic_id, physical_filename, thumbnail, filesize
 0824              FROM ' . ATTACHMENTS_TABLE . '
 0825              WHERE ' . $db->sql_in_set($sql_id, $ids);
 0826          $result = $db->sql_query($sql);
 0827   
 0828          while ($row = $db->sql_fetchrow($result))
 0829          {
 0830              $post_ids[] = $row['post_id'];
 0831              $topic_ids[] = $row['topic_id'];
 0832              $physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize']);
 0833          }
 0834          $db->sql_freeresult($result);
 0835      }
 0836   
 0837      if ($mode == 'post')
 0838      {
 0839          $sql = 'SELECT topic_id, physical_filename, thumbnail, filesize
 0840              FROM ' . ATTACHMENTS_TABLE . '
 0841              WHERE ' . $db->sql_in_set('post_msg_id', $ids) . '
 0842                  AND in_message = 0';
 0843          $result = $db->sql_query($sql);
 0844   
 0845          while ($row = $db->sql_fetchrow($result))
 0846          {
 0847              $topic_ids[] = $row['topic_id'];
 0848              $physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize']);
 0849          }
 0850          $db->sql_freeresult($result);
 0851      }
 0852   
 0853      // Delete attachments
 0854      $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
 0855          WHERE ' . $db->sql_in_set($sql_id, $ids);
 0856      $db->sql_query($sql);
 0857      $num_deleted = $db->sql_affectedrows();
 0858   
 0859      if (!$num_deleted)
 0860      {
 0861          return 0;
 0862      }
 0863   
 0864      // Delete attachments from filesystem
 0865      $space_removed = $files_removed = 0;
 0866      foreach ($physical as $file_ary)
 0867      {
 0868          if (phpbb_unlink($file_ary['filename'], 'file', true))
 0869          {
 0870              $space_removed += $file_ary['filesize'];
 0871              $files_removed++;
 0872          }
 0873   
 0874          if ($file_ary['thumbnail'])
 0875          {
 0876              phpbb_unlink($file_ary['filename'], 'thumbnail', true);
 0877          }
 0878      }
 0879      set_config('upload_dir_size', $config['upload_dir_size'] - $space_removed, true);
 0880      set_config('num_files', $config['num_files'] - $files_removed, true);
 0881   
 0882      if ($mode == 'topic' && !$resync)
 0883      {
 0884          return $num_deleted;
 0885      }
 0886   
 0887      if ($mode == 'post')
 0888      {
 0889          $post_ids = $ids;
 0890      }
 0891      unset($ids);
 0892   
 0893      $post_ids = array_unique($post_ids);
 0894      $topic_ids = array_unique($topic_ids);
 0895   
 0896      // Update post indicators
 0897      if (sizeof($post_ids))
 0898      {
 0899          if ($mode == 'post' || $mode == 'topic')
 0900          {
 0901              $sql = 'UPDATE ' . POSTS_TABLE . '
 0902                  SET post_attachment = 0
 0903                  WHERE ' . $db->sql_in_set('post_id', $post_ids);
 0904              $db->sql_query($sql);
 0905          }
 0906   
 0907          if ($mode == 'user' || $mode == 'attach')
 0908          {
 0909              $remaining = array();
 0910   
 0911              $sql = 'SELECT post_msg_id
 0912                  FROM ' . ATTACHMENTS_TABLE . '
 0913                  WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
 0914                      AND in_message = 0';
 0915              $result = $db->sql_query($sql);
 0916   
 0917              while ($row = $db->sql_fetchrow($result))
 0918              {
 0919                  $remaining[] = $row['post_msg_id'];        
 0920              }
 0921              $db->sql_freeresult($result);
 0922   
 0923              $unset_ids = array_diff($post_ids, $remaining);
 0924   
 0925              if (sizeof($unset_ids))
 0926              {
 0927                  $sql = 'UPDATE ' . POSTS_TABLE . '
 0928                      SET post_attachment = 0
 0929                      WHERE ' . $db->sql_in_set('post_id', $unset_ids);
 0930                  $db->sql_query($sql);
 0931              }
 0932   
 0933              $remaining = array();
 0934   
 0935              $sql = 'SELECT post_msg_id
 0936                  FROM ' . ATTACHMENTS_TABLE . '
 0937                  WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
 0938                      AND in_message = 1';
 0939              $result = $db->sql_query($sql);
 0940   
 0941              while ($row = $db->sql_fetchrow($result))
 0942              {
 0943                  $remaining[] = $row['post_msg_id'];        
 0944              }
 0945              $db->sql_freeresult($result);
 0946   
 0947              $unset_ids = array_diff($post_ids, $remaining);
 0948   
 0949              if (sizeof($unset_ids))
 0950              {
 0951                  $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
 0952                      SET message_attachment = 0
 0953                      WHERE ' . $db->sql_in_set('msg_id', $unset_ids);
 0954                  $db->sql_query($sql);
 0955              }
 0956          }
 0957      }
 0958   
 0959      if (sizeof($topic_ids))
 0960      {
 0961          // Update topic indicator
 0962          if ($mode == 'topic')
 0963          {
 0964              $sql = 'UPDATE ' . TOPICS_TABLE . '
 0965                  SET topic_attachment = 0
 0966                  WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
 0967              $db->sql_query($sql);
 0968          }
 0969   
 0970          if ($mode == 'post' || $mode == 'user' || $mode == 'attach')
 0971          {
 0972              $remaining = array();
 0973   
 0974              $sql = 'SELECT topic_id
 0975                  FROM ' . ATTACHMENTS_TABLE . '
 0976                  WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
 0977              $result = $db->sql_query($sql);
 0978   
 0979              while ($row = $db->sql_fetchrow($result))
 0980              {
 0981                  $remaining[] = $row['topic_id'];        
 0982              }
 0983              $db->sql_freeresult($result);
 0984   
 0985              $unset_ids = array_diff($topic_ids, $remaining);
 0986   
 0987              if (sizeof($unset_ids))
 0988              {
 0989                  $sql = 'UPDATE ' . TOPICS_TABLE . '
 0990                      SET topic_attachment = 0
 0991                      WHERE ' . $db->sql_in_set('topic_id', $unset_ids);
 0992                  $db->sql_query($sql);
 0993              }
 0994          }
 0995      }
 0996   
 0997      return $num_deleted;
 0998  }
 0999   
 1000  /**
 1001  * Remove topic shadows
 1002  */
 1003  function delete_topic_shadows($max_age, $forum_id = '', $auto_sync = true)
 1004  {
 1005      $where = (is_array($forum_id)) ? 'AND ' . $db->sql_in_set('t.forum_id', array_map('intval', $forum_id)) : (($forum_id) ? 'AND t.forum_id = ' . (int) $forum_id : '');
 1006   
 1007      switch ($db->sql_layer)
 1008      {
 1009          case 'mysql4':
 1010          case 'mysqli':
 1011              $sql = 'DELETE t.*
 1012                  FROM ' . TOPICS_TABLE . ' t, ' . TOPICS_TABLE . ' t2
 1013                  WHERE t.topic_moved_id = t2.topic_id
 1014                      AND t.topic_time < ' . (time() - $max_age)
 1015                  . $where;
 1016              $db->sql_query($sql);
 1017          break;
 1018      
 1019          default:
 1020              $sql = 'SELECT t.topic_id
 1021                  FROM ' . TOPICS_TABLE . ' t, ' . TOPICS_TABLE . ' t2
 1022                  WHERE t.topic_moved_id = t2.topic_id
 1023                      AND t.topic_time < ' . (time() - $max_age)
 1024                  . $where;
 1025              $result = $db->sql_query($sql);
 1026   
 1027              $topic_ids = array();
 1028              while ($row = $db->sql_fetchrow($result))
 1029              {
 1030                  $topic_ids[] = $row['topic_id'];
 1031              }
 1032              $db->sql_freeresult($result);
 1033   
 1034              if (sizeof($topic_ids))
 1035              {
 1036                  $sql = 'DELETE FROM ' . TOPICS_TABLE . '
 1037                      WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
 1038                  $db->sql_query($sql);
 1039              }
 1040          break;
 1041      }
 1042   
 1043      if ($auto_sync)
 1044      {
 1045          $where_type = ($forum_id) ? 'forum_id' : '';
 1046          sync('forum', $where_type, $forum_id, true, true);
 1047      }
 1048  }
 1049   
 1050  /**
 1051  * Update/Sync posted information for topics
 1052  */
 1053  function update_posted_info(&$topic_ids)
 1054  {
 1055      global $db, $config;
 1056   
 1057      if (empty($topic_ids) || !$config['load_db_track'])
 1058      {
 1059          return;
 1060      }
 1061   
 1062      // First of all, let us remove any posted information for these topics
 1063      $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . '
 1064          WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
 1065      $db->sql_query($sql);
 1066   
 1067      // Now, let us collect the user/topic combos for rebuilding the information
 1068      $sql = 'SELECT poster_id, topic_id
 1069          FROM ' . POSTS_TABLE . '
 1070          WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
 1071              AND poster_id <> ' . ANONYMOUS . '
 1072          GROUP BY poster_id, topic_id';
 1073      $result = $db->sql_query($sql);
 1074   
 1075      $posted = array();
 1076      while ($row = $db->sql_fetchrow($result))
 1077      {
 1078          // Add as key to make them unique (grouping by) and circumvent empty keys on array_unique
 1079          $posted[$row['poster_id']][] = $row['topic_id'];
 1080      }
 1081      $db->sql_freeresult($result);
 1082   
 1083      // Now add the information...
 1084      $sql_ary = array();
 1085      foreach ($posted as $user_id => $topic_row)
 1086      {
 1087          foreach ($topic_row as $topic_id)
 1088          {
 1089              $sql_ary[] = array(
 1090                  'user_id'        => (int) $user_id,
 1091                  'topic_id'        => (int) $topic_id,
 1092                  'topic_posted'    => 1,
 1093              );
 1094          }
 1095      }
 1096      unset($posted);
 1097   
 1098      $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary);
 1099  }
 1100   
 1101  /**
 1102  * Delete attached file
 1103  */
 1104  function phpbb_unlink($filename, $mode = 'file', $entry_removed = false)
 1105  {
 1106      global $db, $phpbb_root_path, $config;
 1107   
 1108      // Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
 1109      $sql = 'SELECT COUNT(attach_id) AS num_entries
 1110          FROM ' . ATTACHMENTS_TABLE . "
 1111          WHERE physical_filename = '" . $db->sql_escape(basename($filename)) . "'";
 1112      $result = $db->sql_query($sql);
 1113      $num_entries = (int) $db->sql_fetchfield('num_entries');
 1114      $db->sql_freeresult($result);
 1115   
 1116      // Do not remove file if at least one additional entry with the same name exist.
 1117      if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1))
 1118      {
 1119          return false;
 1120      }
 1121   
 1122      $filename = ($mode == 'thumbnail') ? 'thumb_' . basename($filename) : basename($filename);
 1123      return @unlink($phpbb_root_path . $config['upload_path'] . '/' . $filename);
 1124  }
 1125   
 1126  /**
 1127  * All-encompasing sync function
 1128  *
 1129  * Exaples:
 1130  * <code>
 1131  * sync('topic', 'topic_id', 123);            // resync topic #123
 1132  * sync('topic', 'forum_id', array(2, 3));    // resync topics from forum #2 and #3
 1133  * sync('topic');                            // resync all topics
 1134  * sync('topic', 'range', 'topic_id BETWEEN 1 AND 60');    // resync a range of topics/forums (only available for 'topic' and 'forum' modes)
 1135  * </code>
 1136  *
 1137  * Modes:
 1138  * - forum                Resync complete forum
 1139  * - topic                Resync topics
 1140  * - topic_moved            Removes topic shadows that would be in the same forum as the topic they link to
 1141  * - topic_approved        Resyncs the topic_approved flag according to the status of the first post
 1142  * - post_reported        Resyncs the post_reported flag, relying on actual reports
 1143  * - topic_reported        Resyncs the topic_reported flag, relying on post_reported flags
 1144  * - post_attachement    Same as post_reported, but with attachment flags
 1145  * - topic_attachement    Same as topic_reported, but with attachment flags
 1146  */
 1147  function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $sync_extra = false)
 1148  {
 1149      global $db;
 1150   
 1151      if (is_array($where_ids))
 1152      {
 1153          $where_ids = array_unique($where_ids);
 1154          $where_ids = array_map('intval', $where_ids);
 1155      }
 1156      else if ($where_type != 'range')
 1157      {
 1158          $where_ids = ($where_ids) ? array((int) $where_ids) : array();
 1159      }
 1160   
 1161      if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_approved' || $mode == 'topic_reported' || $mode == 'post_reported')
 1162      {
 1163          if (!$where_type)
 1164          {
 1165              $where_sql = '';
 1166              $where_sql_and = 'WHERE';
 1167          }
 1168          else if ($where_type == 'range')
 1169          {
 1170              // Only check a range of topics/forums. For instance: 'topic_id BETWEEN 1 AND 60'
 1171              $where_sql = 'WHERE (' . $mode[0] . ".$where_ids)";
 1172              $where_sql_and = $where_sql . "\n\tAND";
 1173          }
 1174          else
 1175          {
 1176              // Do not sync the "global forum"
 1177              $where_ids = array_diff($where_ids, array(0));
 1178   
 1179              if (!sizeof($where_ids))
 1180              {
 1181                  // Empty array with IDs. This means that we don't have any work to do. Just return.
 1182                  return;
 1183              }
 1184   
 1185              // Limit the topics/forums we are syncing, use specific topic/forum IDs.
 1186              // $where_type contains the field for the where clause (forum_id, topic_id)
 1187              $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids);
 1188              $where_sql_and = $where_sql . "\n\tAND";
 1189          }
 1190      }
 1191      else
 1192      {
 1193          if (!sizeof($where_ids))
 1194          {
 1195              return;
 1196          }
 1197   
 1198          // $where_type contains the field for the where clause (forum_id, topic_id)
 1199          $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids);
 1200          $where_sql_and = $where_sql . "\n\tAND";
 1201      }
 1202   
 1203      switch ($mode)
 1204      {
 1205          case 'topic_moved':
 1206              switch ($db->sql_layer)
 1207              {
 1208                  case 'mysql4':
 1209                  case 'mysqli':
 1210                      $sql = 'DELETE FROM ' . TOPICS_TABLE . '
 1211                          USING ' . TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2
 1212                          WHERE t1.topic_moved_id = t2.topic_id
 1213                              AND t1.forum_id = t2.forum_id";
 1214                      $db->sql_query($sql);
 1215                  break;
 1216              
 1217                  default:
 1218                      $sql = 'SELECT t1.topic_id
 1219                          FROM ' .TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2
 1220                          WHERE t1.topic_moved_id = t2.topic_id
 1221                              AND t1.forum_id = t2.forum_id";
 1222                      $result = $db->sql_query($sql);
 1223   
 1224                      $topic_id_ary = array();
 1225                      while ($row = $db->sql_fetchrow($result))
 1226                      {
 1227                          $topic_id_ary[] = $row['topic_id'];
 1228                      }
 1229                      $db->sql_freeresult($result);
 1230   
 1231                      if (!sizeof($topic_id_ary))
 1232                      {
 1233                          return;
 1234                      }
 1235   
 1236                      $sql = 'DELETE FROM ' . TOPICS_TABLE . '
 1237                          WHERE ' . $db->sql_in_set('topic_id', $topic_id_ary);
 1238                      $db->sql_query($sql);
 1239   
 1240                  break;
 1241              }
 1242          break;
 1243   
 1244          case 'topic_approved':
 1245              switch ($db->sql_layer)
 1246              {
 1247                  case 'mysql4':
 1248                  case 'mysqli':
 1249                      $sql = 'UPDATE ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
 1250                          SET t.topic_approved = p.post_approved
 1251                          $where_sql_and t.topic_first_post_id = p.post_id";
 1252                      $db->sql_query($sql);
 1253                  break;
 1254   
 1255                  default:
 1256                      $sql = 'SELECT t.topic_id, p.post_approved
 1257                          FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
 1258                          $where_sql_and p.post_id = t.topic_first_post_id
 1259                              AND p.post_approved <> t.topic_approved";
 1260                      $result = $db->sql_query($sql);
 1261   
 1262                      $topic_ids = array();
 1263                      while ($row = $db->sql_fetchrow($result))
 1264                      {
 1265                          $topic_ids[] = $row['topic_id'];
 1266                      }
 1267                      $db->sql_freeresult($result);
 1268   
 1269                      if (!sizeof($topic_ids))
 1270                      {
 1271                          return;
 1272                      }
 1273   
 1274                      $sql = 'UPDATE ' . TOPICS_TABLE . '
 1275                          SET topic_approved = 1 - topic_approved
 1276                          WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
 1277                      $db->sql_query($sql);
 1278                  break;
 1279              }
 1280          break;
 1281   
 1282          case 'post_reported':
 1283              $post_ids = $post_reported = array();
 1284   
 1285              $sql = 'SELECT p.post_id, p.post_reported
 1286                  FROM ' . POSTS_TABLE . " p
 1287                  $where_sql
 1288                  GROUP BY p.post_id, p.post_reported";
 1289              $result = $db->sql_query($sql);
 1290   
 1291              while ($row = $db->sql_fetchrow($result))
 1292              {
 1293                  $post_ids[$row['post_id']] = $row['post_id'];
 1294                  if ($row['post_reported'])
 1295                  {
 1296                      $post_reported[$row['post_id']] = 1;
 1297                  }
 1298              }
 1299              $db->sql_freeresult($result);
 1300   
 1301              $sql = 'SELECT DISTINCT(post_id)
 1302                  FROM ' . REPORTS_TABLE . '
 1303                  WHERE ' . $db->sql_in_set('post_id', $post_ids) . '
 1304                      AND report_closed = 0';
 1305              $result = $db->sql_query($sql);
 1306   
 1307              $post_ids = array();
 1308              while ($row = $db->sql_fetchrow($result))
 1309              {
 1310                  if (!isset($post_reported[$row['post_id']]))
 1311                  {
 1312                      $post_ids[] = $row['post_id'];
 1313                  }
 1314                  else
 1315                  {
 1316                      unset($post_reported[$row['post_id']]);
 1317                  }
 1318              }
 1319              $db->sql_freeresult($result);
 1320   
 1321              // $post_reported should be empty by now, if it's not it contains
 1322              // posts that are falsely flagged as reported
 1323              foreach ($post_reported as $post_id => $void)
 1324              {
 1325                  $post_ids[] = $post_id;
 1326              }
 1327   
 1328              if (sizeof($post_ids))
 1329              {
 1330                  $sql = 'UPDATE ' . POSTS_TABLE . '
 1331                      SET post_reported = 1 - post_reported
 1332                      WHERE ' . $db->sql_in_set('post_id', $post_ids);
 1333                  $db->sql_query($sql);
 1334              }
 1335          break;
 1336   
 1337          case 'topic_reported':
 1338              if ($sync_extra)
 1339              {
 1340                  sync('post_reported', $where_type, $where_ids);
 1341              }
 1342   
 1343              $topic_ids = $topic_reported = array();
 1344   
 1345              $sql = 'SELECT DISTINCT(t.topic_id)
 1346                  FROM ' . POSTS_TABLE . " t
 1347                  $where_sql_and t.post_reported = 1";
 1348              $result = $db->sql_query($sql);
 1349   
 1350              while ($row = $db->sql_fetchrow($result))
 1351              {
 1352                  $topic_reported[$row['topic_id']] = 1;
 1353              }
 1354              $db->sql_freeresult($result);
 1355   
 1356              $sql = 'SELECT t.topic_id, t.topic_reported
 1357                  FROM ' . TOPICS_TABLE . " t
 1358                  $where_sql";
 1359              $result = $db->sql_query($sql);
 1360   
 1361              while ($row = $db->sql_fetchrow($result))
 1362              {
 1363                  if ($row['topic_reported'] ^ isset($topic_reported[$row['topic_id']]))
 1364                  {
 1365                      $topic_ids[] = $row['topic_id'];
 1366                  }
 1367              }
 1368              $db->sql_freeresult($result);
 1369   
 1370              if (sizeof($topic_ids))
 1371              {
 1372                  $sql = 'UPDATE ' . TOPICS_TABLE . '
 1373                      SET topic_reported = 1 - topic_reported
 1374                      WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
 1375                  $db->sql_query($sql);
 1376              }
 1377          break;
 1378   
 1379          case 'post_attachment':
 1380              $post_ids = $post_attachment = array();
 1381   
 1382              $sql = 'SELECT p.post_id, p.post_attachment
 1383                  FROM ' . POSTS_TABLE . " p
 1384                  $where_sql
 1385                  GROUP BY p.post_id, p.post_attachment";
 1386              $result = $db->sql_query($sql);
 1387   
 1388              while ($row = $db->sql_fetchrow($result))
 1389              {
 1390                  $post_ids[$row['post_id']] = $row['post_id'];
 1391                  if ($row['post_attachment'])
 1392                  {
 1393                      $post_attachment[$row['post_id']] = 1;
 1394                  }
 1395              }
 1396              $db->sql_freeresult($result);
 1397   
 1398              $sql = 'SELECT DISTINCT(post_msg_id)
 1399                  FROM ' . ATTACHMENTS_TABLE . '
 1400                  WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
 1401                      AND in_message = 0';
 1402              $result = $db->sql_query($sql);
 1403   
 1404              $post_ids = array();
 1405              while ($row = $db->sql_fetchrow($result))
 1406              {
 1407                  if (!isset($post_attachment[$row['post_msg_id']]))
 1408                  {
 1409                      $post_ids[] = $row['post_msg_id'];
 1410                  }
 1411                  else
 1412                  {
 1413                      unset($post_attachment[$row['post_msg_id']]);
 1414                  }
 1415              }
 1416              $db->sql_freeresult($result);
 1417   
 1418              // $post_attachment should be empty by now, if it's not it contains
 1419              // posts that are falsely flagged as having attachments
 1420              foreach ($post_attachment as $post_id => $void)
 1421              {
 1422                  $post_ids[] = $post_id;
 1423              }
 1424   
 1425              if (sizeof($post_ids))
 1426              {
 1427                  $sql = 'UPDATE ' . POSTS_TABLE . '
 1428                      SET post_attachment = 1 - post_attachment
 1429                      WHERE ' . $db->sql_in_set('post_id', $post_ids);
 1430                  $db->sql_query($sql);
 1431              }
 1432          break;
 1433   
 1434          case 'topic_attachment':
 1435              if ($sync_extra)
 1436              {
 1437                  sync('post_attachment', $where_type, $where_ids);
 1438              }
 1439   
 1440              $topic_ids = $topic_attachment = array();
 1441   
 1442              $sql = 'SELECT DISTINCT(t.topic_id)
 1443                  FROM ' . POSTS_TABLE . " t
 1444                  $where_sql_and t.post_attachment = 1";
 1445              $result = $db->sql_query($sql);
 1446   
 1447              while ($row = $db->sql_fetchrow($result))
 1448              {
 1449                  $topic_attachment[$row['topic_id']] = 1;
 1450              }
 1451              $db->sql_freeresult($result);
 1452   
 1453              $sql = 'SELECT t.topic_id, t.topic_attachment
 1454                  FROM ' . TOPICS_TABLE . " t
 1455                  $where_sql";
 1456              $result = $db->sql_query($sql);
 1457   
 1458              while ($row = $db->sql_fetchrow($result))
 1459              {
 1460                  if ($row['topic_attachment'] ^ isset($topic_attachment[$row['topic_id']]))
 1461                  {
 1462                      $topic_ids[] = $row['topic_id'];
 1463                  }
 1464              }
 1465              $db->sql_freeresult($result);
 1466   
 1467              if (sizeof($topic_ids))
 1468              {
 1469                  $sql = 'UPDATE ' . TOPICS_TABLE . '
 1470                      SET topic_attachment = 1 - topic_attachment
 1471                      WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
 1472                  $db->sql_query($sql);
 1473              }
 1474          break;
 1475   
 1476          case 'forum':
 1477   
 1478              // 1: Get the list of all forums
 1479              $sql = 'SELECT f.*
 1480                  FROM ' . FORUMS_TABLE . " f
 1481                  $where_sql";
 1482              $result = $db->sql_query($sql);
 1483   
 1484              $forum_data = $forum_ids = $post_ids = $last_post_id = $post_info = array();
 1485              while ($row = $db->sql_fetchrow($result))
 1486              {
 1487                  if ($row['forum_type'] == FORUM_LINK)
 1488                  {
 1489                      continue;
 1490                  }
 1491   
 1492                  $forum_id = (int) $row['forum_id'];
 1493                  $forum_ids[$forum_id] = $forum_id;
 1494   
 1495                  $forum_data[$forum_id] = $row;
 1496                  if ($sync_extra)
 1497                  {
 1498                      $forum_data[$forum_id]['posts'] = 0;
 1499                      $forum_data[$forum_id]['topics'] = 0;
 1500                      $forum_data[$forum_id]['topics_real'] = 0;
 1501                  }
 1502                  $forum_data[$forum_id]['last_post_id'] = 0;
 1503                  $forum_data[$forum_id]['last_post_subject'] = '';
 1504                  $forum_data[$forum_id]['last_post_time'] = 0;
 1505                  $forum_data[$forum_id]['last_poster_id'] = 0;
 1506                  $forum_data[$forum_id]['last_poster_name'] = '';
 1507                  $forum_data[$forum_id]['last_poster_colour'] = '';
 1508              }
 1509              $db->sql_freeresult($result);
 1510   
 1511              if (!sizeof($forum_ids))
 1512              {
 1513                  break;
 1514              }
 1515   
 1516              $forum_ids = array_values($forum_ids);
 1517   
 1518              // 2: Get topic counts for each forum (optional)
 1519              if ($sync_extra)
 1520              {
 1521                  $sql = 'SELECT forum_id, topic_approved, COUNT(topic_id) AS forum_topics
 1522                      FROM ' . TOPICS_TABLE . '
 1523                      WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . '
 1524                      GROUP BY forum_id, topic_approved';
 1525                  $result = $db->sql_query($sql);
 1526   
 1527                  while ($row = $db->sql_fetchrow($result))
 1528                  {
 1529                      $forum_id = (int) $row['forum_id'];
 1530                      $forum_data[$forum_id]['topics_real'] += $row['forum_topics'];
 1531   
 1532                      if ($row['topic_approved'])
 1533                      {
 1534                          $forum_data[$forum_id]['topics'] = $row['forum_topics'];
 1535                      }
 1536                  }
 1537                  $db->sql_freeresult($result);
 1538              }
 1539   
 1540              // 3: Get post count for each forum (optional)
 1541              if ($sync_extra)
 1542              {
 1543                  if (sizeof($forum_ids) == 1)
 1544                  {
 1545                      $sql = 'SELECT SUM(t.topic_replies + 1) AS forum_posts
 1546                          FROM ' . TOPICS_TABLE . ' t
 1547                          WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
 1548                              AND t.topic_approved = 1';
 1549                  }
 1550                  else
 1551                  {
 1552                      $sql = 'SELECT t.forum_id, SUM(t.topic_replies + 1) AS forum_posts
 1553                          FROM ' . TOPICS_TABLE . ' t
 1554                          WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
 1555                              AND t.topic_approved = 1
 1556                          GROUP BY t.forum_id';
 1557                  }
 1558   
 1559                  $result = $db->sql_query($sql);
 1560   
 1561                  while ($row = $db->sql_fetchrow($result))
 1562                  {
 1563                      $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
 1564   
 1565                      $forum_data[$forum_id]['posts'] = (int) $row['forum_posts'];
 1566                  }
 1567                  $db->sql_freeresult($result);
 1568              }
 1569   
 1570              // 4: Get last_post_id for each forum
 1571              if (sizeof($forum_ids) == 1)
 1572              {
 1573                  $sql = 'SELECT MAX(t.topic_last_post_id) as last_post_id
 1574                      FROM ' . TOPICS_TABLE . ' t
 1575                      WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
 1576                          AND t.topic_approved = 1';
 1577              }
 1578              else
 1579              {
 1580                  $sql = 'SELECT t.forum_id, MAX(t.topic_last_post_id) as last_post_id
 1581                      FROM ' . TOPICS_TABLE . ' t
 1582                      WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
 1583                          AND t.topic_approved = 1
 1584                      GROUP BY t.forum_id';
 1585              }
 1586   
 1587              $result = $db->sql_query($sql);
 1588   
 1589              while ($row = $db->sql_fetchrow($result))
 1590              {
 1591                  $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
 1592   
 1593                  $forum_data[$forum_id]['last_post_id'] = (int) $row['last_post_id'];
 1594   
 1595                  $post_ids[] = $row['last_post_id'];
 1596              }
 1597              $db->sql_freeresult($result);
 1598   
 1599              // 5: Retrieve last_post infos
 1600              if (sizeof($post_ids))
 1601              {
 1602                  $sql = 'SELECT p.post_id, p.poster_id, p.post_subject, p.post_time, p.post_username, u.username, u.user_colour
 1603                      FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
 1604                      WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
 1605                          AND p.poster_id = u.user_id';
 1606                  $result = $db->sql_query($sql);
 1607   
 1608                  while ($row = $db->sql_fetchrow($result))
 1609                  {
 1610                      $post_info[$row['post_id']] = $row;
 1611                  }
 1612                  $db->sql_freeresult($result);
 1613   
 1614                  foreach ($forum_data as $forum_id => $data)
 1615                  {
 1616                      if ($data['last_post_id'])
 1617                      {
 1618                          if (isset($post_info[$data['last_post_id']]))
 1619                          {
 1620                              $forum_data[$forum_id]['last_post_subject'] = $post_info[$data['last_post_id']]['post_subject'];
 1621                              $forum_data[$forum_id]['last_post_time'] = $post_info[$data['last_post_id']]['post_time'];
 1622                              $forum_data[$forum_id]['last_poster_id'] = $post_info[$data['last_post_id']]['poster_id'];
 1623                              $forum_data[$forum_id]['last_poster_name'] = ($post_info[$data['last_post_id']]['poster_id'] != ANONYMOUS) ? $post_info[$data['last_post_id']]['username'] : $post_info[$data['last_post_id']]['post_username'];
 1624                              $forum_data[$forum_id]['last_poster_colour'] = $post_info[$data['last_post_id']]['user_colour'];
 1625                          }
 1626                          else
 1627                          {
 1628                              // For some reason we did not find the post in the db
 1629                              $forum_data[$forum_id]['last_post_id'] = 0;
 1630                              $forum_data[$forum_id]['last_post_subject'] = '';
 1631                              $forum_data[$forum_id]['last_post_time'] = 0;
 1632                              $forum_data[$forum_id]['last_poster_id'] = 0;
 1633                              $forum_data[$forum_id]['last_poster_name'] = '';
 1634                              $forum_data[$forum_id]['last_poster_colour'] = '';
 1635                          }
 1636                      }
 1637                  }
 1638                  unset($post_info);
 1639              }
 1640   
 1641              // 6: Now do that thing
 1642              $fieldnames = array('last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour');
 1643   
 1644              if ($sync_extra)
 1645              {
 1646                  array_push($fieldnames, 'posts', 'topics', 'topics_real');
 1647              }
 1648   
 1649              foreach ($forum_data as $forum_id => $row)
 1650              {
 1651                  $sql_ary = array();
 1652   
 1653                  foreach ($fieldnames as $fieldname)
 1654                  {
 1655                      if ($row['forum_' . $fieldname] != $row[$fieldname])
 1656                      {
 1657                          if (preg_match('#(name|colour|subject)$#', $fieldname))
 1658                          {
 1659                              $sql_ary['forum_' . $fieldname] = (string) $row[$fieldname];
 1660                          }
 1661                          else
 1662                          {
 1663                              $sql_ary['forum_' . $fieldname] = (int) $row[$fieldname];
 1664                          }
 1665                      }
 1666                  }
 1667   
 1668                  if (sizeof($sql_ary))
 1669                  {
 1670                      $sql = 'UPDATE ' . FORUMS_TABLE . '
 1671                          SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
 1672                          WHERE forum_id = ' . $forum_id;
 1673                      $db->sql_query($sql);
 1674                  }
 1675              }
 1676          break;
 1677   
 1678          case 'topic':
 1679              $topic_data = $post_ids = $approved_unapproved_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array();
 1680   
 1681              $sql = 'SELECT t.topic_id, t.forum_id, t.topic_moved_id, t.topic_approved, ' . (($sync_extra) ? 't.topic_attachment, t.topic_reported, ' : '') . 't.topic_poster, t.topic_time, t.topic_replies, t.topic_replies_real, t.topic_first_post_id, t.topic_first_poster_name, t.topic_first_poster_colour, t.topic_last_post_id, t.topic_last_post_subject, t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_poster_colour, t.topic_last_post_time
 1682                  FROM ' . TOPICS_TABLE . " t
 1683                  $where_sql";
 1684              $result = $db->sql_query($sql);
 1685   
 1686              while ($row = $db->sql_fetchrow($result))
 1687              {
 1688                  if ($row['topic_moved_id'])
 1689                  {
 1690                      $moved_topics[] = $row['topic_id'];
 1691                      continue;
 1692                  }
 1693   
 1694                  $topic_id = (int) $row['topic_id'];
 1695                  $topic_data[$topic_id] = $row;
 1696                  $topic_data[$topic_id]['replies_real'] = -1;
 1697                  $topic_data[$topic_id]['replies'] = 0;
 1698                  $topic_data[$topic_id]['first_post_id'] = 0;
 1699                  $topic_data[$topic_id]['last_post_id'] = 0;
 1700                  unset($topic_data[$topic_id]['topic_id']);
 1701   
 1702                  // This array holds all topic_ids
 1703                  $delete_topics[$topic_id] = '';
 1704   
 1705                  if ($sync_extra)
 1706                  {
 1707                      $topic_data[$topic_id]['reported'] = 0;
 1708                      $topic_data[$topic_id]['attachment'] = 0;
 1709                  }
 1710              }
 1711              $db->sql_freeresult($result);
 1712   
 1713              // Use "t" as table alias because of the $where_sql clause
 1714              // NOTE: 't.post_approved' in the GROUP BY is causing a major slowdown.
 1715              $sql = 'SELECT t.topic_id, t.post_approved, COUNT(t.post_id) AS total_posts, MIN(t.post_id) AS first_post_id, MAX(t.post_id) AS last_post_id
 1716                  FROM ' . POSTS_TABLE . " t
 1717                  $where_sql
 1718                  GROUP BY t.topic_id, t.post_approved";
 1719              $result = $db->sql_query($sql);
 1720   
 1721              while ($row = $db->sql_fetchrow($result))
 1722              {
 1723                  $topic_id = (int) $row['topic_id'];
 1724   
 1725                  $row['first_post_id'] = (int) $row['first_post_id'];
 1726                  $row['last_post_id'] = (int) $row['last_post_id'];
 1727   
 1728                  if (!isset($topic_data[$topic_id]))
 1729                  {
 1730                      // Hey, these posts come from a topic that does not exist
 1731                      $delete_posts[$topic_id] = '';
 1732                  }
 1733                  else
 1734                  {
 1735                      // Unset the corresponding entry in $delete_topics
 1736                      // When we'll be done, only topics with no posts will remain
 1737                      unset($delete_topics[$topic_id]);
 1738   
 1739                      $topic_data[$topic_id]['replies_real'] += $row['total_posts'];
 1740                      $topic_data[$topic_id]['first_post_id'] = (!$topic_data[$topic_id]['first_post_id']) ? $row['first_post_id'] : min($topic_data[$topic_id]['first_post_id'], $row['first_post_id']);
 1741   
 1742                      if ($row['post_approved'] || !$topic_data[$topic_id]['last_post_id'])
 1743                      {
 1744                          $topic_data[$topic_id]['replies'] = $row['total_posts'] - 1;
 1745                          $topic_data[$topic_id]['last_post_id'] = $row['last_post_id'];
 1746                      }
 1747                  }
 1748              }
 1749              $db->sql_freeresult($result);
 1750   
 1751              foreach ($topic_data as $topic_id => $row)
 1752              {
 1753                  $post_ids[] = $row['first_post_id'];
 1754                  if ($row['first_post_id'] != $row['last_post_id'])
 1755                  {
 1756                      $post_ids[] = $row['last_post_id'];
 1757                  }
 1758              }
 1759   
 1760              // Now we delete empty topics and orphan posts
 1761              if (sizeof($delete_posts))
 1762              {
 1763                  delete_posts('topic_id', array_keys($delete_posts), false);
 1764                  unset($delete_posts);
 1765              }
 1766   
 1767              if (!sizeof($topic_data))
 1768              {
 1769                  // If we get there, topic ids were invalid or topics did not contain any posts
 1770                  delete_topics($where_type, $where_ids, true);
 1771                  return;
 1772              }
 1773   
 1774              if (sizeof($delete_topics))
 1775              {
 1776                  $delete_topic_ids = array();
 1777                  foreach ($delete_topics as $topic_id => $void)
 1778                  {
 1779                      unset($topic_data[$topic_id]);
 1780                      $delete_topic_ids[] = $topic_id;
 1781                  }
 1782   
 1783                  delete_topics('topic_id', $delete_topic_ids, false);
 1784                  unset($delete_topics, $delete_topic_ids);
 1785              }
 1786   
 1787              $sql = 'SELECT p.post_id, p.topic_id, p.post_approved, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour
 1788                  FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
 1789                  WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
 1790                      AND u.user_id = p.poster_id';
 1791              $result = $db->sql_query($sql);
 1792   
 1793              $post_ids = array();
 1794              while ($row = $db->sql_fetchrow($result))
 1795              {
 1796                  $topic_id = intval($row['topic_id']);
 1797   
 1798                  if ($row['post_id'] == $topic_data[$topic_id]['first_post_id'])
 1799                  {
 1800                      if ($topic_data[$topic_id]['topic_approved'] != $row['post_approved'])
 1801                      {
 1802                          $approved_unapproved_ids[] = $topic_id;
 1803                      }
 1804                      $topic_data[$topic_id]['time'] = $row['post_time'];
 1805                      $topic_data[$topic_id]['poster'] = $row['poster_id'];
 1806                      $topic_data[$topic_id]['first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
 1807                      $topic_data[$topic_id]['first_poster_colour'] = $row['user_colour'];
 1808                  }
 1809   
 1810                  if ($row['post_id'] == $topic_data[$topic_id]['last_post_id'])
 1811                  {
 1812                      $topic_data[$topic_id]['last_poster_id'] = $row['poster_id'];
 1813                      $topic_data[$topic_id]['last_post_subject'] = $row['post_subject'];
 1814                      $topic_data[$topic_id]['last_post_time'] = $row['post_time'];
 1815                      $topic_data[$topic_id]['last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
 1816                      $topic_data[$topic_id]['last_poster_colour'] = $row['user_colour'];
 1817                  }
 1818              }
 1819              $db->sql_freeresult($result);
 1820   
 1821              // Make sure shadow topics do link to existing topics
 1822              if (sizeof($moved_topics))
 1823              {
 1824                  $delete_topics = array();
 1825   
 1826                  $sql = 'SELECT t1.topic_id, t1.topic_moved_id
 1827                      FROM ' . TOPICS_TABLE . ' t1
 1828                      LEFT JOIN ' . TOPICS_TABLE . ' t2 ON (t2.topic_id = t1.topic_moved_id)
 1829                      WHERE ' . $db->sql_in_set('t1.topic_id', $moved_topics) . '
 1830                          AND t2.topic_id IS NULL';
 1831                  $result = $db->sql_query($sql);
 1832   
 1833                  while ($row = $db->sql_fetchrow($result))
 1834                  {
 1835                      $delete_topics[] = $row['topic_id'];
 1836                  }
 1837                  $db->sql_freeresult($result);
 1838   
 1839                  if (sizeof($delete_topics))
 1840                  {
 1841                      delete_topics('topic_id', $delete_topics, false);
 1842                  }
 1843                  unset($delete_topics);
 1844   
 1845                  // Make sure shadow topics having no last post data being updated (this only rarely happens...)
 1846                  $sql = 'SELECT topic_id, topic_moved_id, topic_last_post_id, topic_first_post_id
 1847                      FROM ' . TOPICS_TABLE . '
 1848                      WHERE ' . $db->sql_in_set('topic_id', $moved_topics) . '
 1849                          AND topic_last_post_time = 0';
 1850                  $result = $db->sql_query($sql);
 1851   
 1852                  $shadow_topic_data = $post_ids = array();
 1853                  while ($row = $db->sql_fetchrow($result))
 1854                  {
 1855                      $shadow_topic_data[$row['topic_moved_id']] = $row;
 1856                      $post_ids[] = $row['topic_last_post_id'];
 1857                      $post_ids[] = $row['topic_first_post_id'];
 1858                  }
 1859                  $db->sql_freeresult($result);
 1860   
 1861                  $sync_shadow_topics = array();
 1862                  if (sizeof($post_ids))
 1863                  {
 1864                      $sql = 'SELECT p.post_id, p.topic_id, p.post_approved, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour
 1865                          FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
 1866                          WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
 1867                              AND u.user_id = p.poster_id';
 1868                      $result = $db->sql_query($sql);
 1869   
 1870                      $post_ids = array();
 1871                      while ($row = $db->sql_fetchrow($result))
 1872                      {
 1873                          $topic_id = (int) $row['topic_id'];
 1874   
 1875                          // Ok, there should be a shadow topic. If there isn't, then there's something wrong with the db.
 1876                          // However, there's not much we can do about it.
 1877                          if (!empty($shadow_topic_data[$topic_id]))
 1878                          {
 1879                              if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_first_post_id'])
 1880                              {
 1881                                  $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id'];
 1882   
 1883                                  if (!isset($sync_shadow_topics[$orig_topic_id]))
 1884                                  {
 1885                                      $sync_shadow_topics[$orig_topic_id] = array();
 1886                                  }
 1887   
 1888                                  $sync_shadow_topics[$orig_topic_id]['topic_time'] = $row['post_time'];
 1889                                  $sync_shadow_topics[$orig_topic_id]['topic_poster'] = $row['poster_id'];
 1890                                  $sync_shadow_topics[$orig_topic_id]['topic_first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
 1891                                  $sync_shadow_topics[$orig_topic_id]['topic_first_poster_colour'] = $row['user_colour'];
 1892                              }
 1893   
 1894                              if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_last_post_id'])
 1895                              {
 1896                                  $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id'];
 1897   
 1898                                  if (!isset($sync_shadow_topics[$orig_topic_id]))
 1899                                  {
 1900                                      $sync_shadow_topics[$orig_topic_id] = array();
 1901                                  }
 1902   
 1903                                  $sync_shadow_topics[$orig_topic_id]['topic_last_poster_id'] = $row['poster_id'];
 1904                                  $sync_shadow_topics[$orig_topic_id]['topic_last_post_subject'] = $row['post_subject'];
 1905                                  $sync_shadow_topics[$orig_topic_id]['topic_last_post_time'] = $row['post_time'];
 1906                                  $sync_shadow_topics[$orig_topic_id]['topic_last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
 1907                                  $sync_shadow_topics[$orig_topic_id]['topic_last_poster_colour'] = $row['user_colour'];
 1908                              }
 1909                          }
 1910                      }
 1911                      $db->sql_freeresult($result);
 1912   
 1913                      $shadow_topic_data = array();
 1914   
 1915                      // Update the information we collected
 1916                      if (sizeof($sync_shadow_topics))
 1917                      {
 1918                          foreach ($sync_shadow_topics as $sync_topic_id => $sql_ary)
 1919                          {
 1920                              $sql = 'UPDATE ' . TOPICS_TABLE . '
 1921                                  SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
 1922                                  WHERE topic_id = ' . $sync_topic_id;
 1923                              $db->sql_query($sql);
 1924                          }
 1925                      }
 1926                  }
 1927   
 1928                  unset($sync_shadow_topics, $shadow_topic_data);
 1929              }
 1930   
 1931              // approved becomes unapproved, and vice-versa
 1932              if (sizeof($approved_unapproved_ids))
 1933              {
 1934                  $sql = 'UPDATE ' . TOPICS_TABLE . '
 1935                      SET topic_approved = 1 - topic_approved
 1936                      WHERE ' . $db->sql_in_set('topic_id', $approved_unapproved_ids);
 1937                  $db->sql_query($sql);
 1938              }
 1939              unset($approved_unapproved_ids);
 1940   
 1941              // These are fields that will be synchronised
 1942              $fieldnames = array('time', 'replies', 'replies_real', 'poster', 'first_post_id', 'first_poster_name', 'first_poster_colour', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour');
 1943   
 1944              if ($sync_extra)
 1945              {
 1946                  // This routine assumes that post_reported values are correct
 1947                  // if they are not, use sync('post_reported') first
 1948                  $sql = 'SELECT t.topic_id, p.post_id
 1949                      FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
 1950                      $where_sql_and p.topic_id = t.topic_id
 1951                          AND p.post_reported = 1
 1952                      GROUP BY t.topic_id, p.post_id";
 1953                  $result = $db->sql_query($sql);
 1954   
 1955                  $fieldnames[] = 'reported';
 1956                  while ($row = $db->sql_fetchrow($result))
 1957                  {
 1958                      $topic_data[intval($row['topic_id'])]['reported'] = 1;
 1959                  }
 1960                  $db->sql_freeresult($result);
 1961   
 1962                  // This routine assumes that post_attachment values are correct
 1963                  // if they are not, use sync('post_attachment') first
 1964                  $sql = 'SELECT t.topic_id, p.post_id
 1965                      FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
 1966                      $where_sql_and p.topic_id = t.topic_id
 1967                          AND p.post_attachment = 1
 1968                      GROUP BY t.topic_id, p.post_id";
 1969                  $result = $db->sql_query($sql);
 1970   
 1971                  $fieldnames[] = 'attachment';
 1972                  while ($row = $db->sql_fetchrow($result))
 1973                  {
 1974                      $topic_data[intval($row['topic_id'])]['attachment'] = 1;
 1975                  }
 1976                  $db->sql_freeresult($result);
 1977              }
 1978   
 1979              foreach ($topic_data as $topic_id => $row)
 1980              {
 1981                  $sql_ary = array();
 1982   
 1983                  foreach ($fieldnames as $fieldname)
 1984                  {
 1985                      if (isset($row[$fieldname]) && isset($row['topic_' . $fieldname]) && $row['topic_' . $fieldname] != $row[$fieldname])
 1986                      {
 1987                          $sql_ary['topic_' . $fieldname] = $row[$fieldname];
 1988                      }
 1989                  }
 1990   
 1991                  if (sizeof($sql_ary))
 1992                  {
 1993                      $sql = 'UPDATE ' . TOPICS_TABLE . '
 1994                          SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
 1995                          WHERE topic_id = ' . $topic_id;
 1996                      $db->sql_query($sql);
 1997   
 1998                      $resync_forums[$row['forum_id']] = $row['forum_id'];
 1999                  }
 2000              }
 2001              unset($topic_data);
 2002   
 2003              // if some topics have been resync'ed then resync parent forums
 2004              // except when we're only syncing a range, we don't want to sync forums during
 2005              // batch processing.
 2006              if ($resync_parents && sizeof($resync_forums) && $where_type != 'range')
 2007              {
 2008                  sync('forum', 'forum_id', array_values($resync_forums), true, true);
 2009              }
 2010          break;
 2011      }
 2012   
 2013      return;
 2014  }
 2015   
 2016  /**
 2017  * Prune function
 2018  */
 2019  function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync = true)
 2020  {
 2021      global $db;
 2022   
 2023      if (!is_array($forum_id))
 2024      {
 2025          $forum_id = array($forum_id);
 2026      }
 2027   
 2028      if (!sizeof($forum_id))
 2029      {
 2030          return;
 2031      }
 2032   
 2033      $sql_and = '';
 2034   
 2035      if (!($prune_flags & FORUM_FLAG_PRUNE_ANNOUNCE))
 2036      {
 2037          $sql_and .= ' AND topic_type <> ' . POST_ANNOUNCE;
 2038      }
 2039   
 2040      if (!($prune_flags & FORUM_FLAG_PRUNE_STICKY))
 2041      {
 2042          $sql_and .= ' AND topic_type <> ' . POST_STICKY;
 2043      }
 2044   
 2045      if ($prune_mode == 'posted')
 2046      {
 2047          $sql_and .= " AND topic_last_post_time < $prune_date";
 2048      }
 2049   
 2050      if ($prune_mode == 'viewed')
 2051      {
 2052          $sql_and .= " AND topic_last_view_time < $prune_date";
 2053      }
 2054   
 2055      $sql = 'SELECT topic_id
 2056          FROM ' . TOPICS_TABLE . '
 2057          WHERE ' . $db->sql_in_set('forum_id', $forum_id) . "
 2058              AND poll_start = 0
 2059              $sql_and";
 2060      $result = $db->sql_query($sql);
 2061   
 2062      $topic_list = array();
 2063      while ($row = $db->sql_fetchrow($result))
 2064      {
 2065          $topic_list[] = $row['topic_id'];
 2066      }
 2067      $db->sql_freeresult($result);
 2068   
 2069      if ($prune_flags & FORUM_FLAG_PRUNE_POLL)
 2070      {
 2071          $sql = 'SELECT topic_id
 2072              FROM ' . TOPICS_TABLE . '
 2073              WHERE ' . $db->sql_in_set('forum_id', $forum_id) . "
 2074                  AND poll_start > 0
 2075                  AND poll_last_vote < $prune_date
 2076                  $sql_and";
 2077          $result = $db->sql_query($sql);
 2078   
 2079          while ($row = $db->sql_fetchrow($result))
 2080          {
 2081              $topic_list[] = $row['topic_id'];
 2082          }
 2083          $db->sql_freeresult($result);
 2084   
 2085          $topic_list = array_unique($topic_list);
 2086      }
 2087   
 2088      return delete_topics('topic_id', $topic_list, $auto_sync, false);
 2089  }
 2090   
 2091  /**
 2092  * Function auto_prune(), this function now relies on passed vars
 2093  */
 2094  function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_freq)
 2095  {
 2096      global $db;
 2097   
 2098      $sql = 'SELECT forum_name
 2099          FROM ' . FORUMS_TABLE . "
 2100          WHERE forum_id = $forum_id";
 2101      $result = $db->sql_query($sql, 3600);
 2102      $row = $db->sql_fetchrow($result);
 2103      $db->sql_freeresult($result);
 2104   
 2105      if ($row)
 2106      {
 2107          $prune_date = time() - ($prune_days * 86400);
 2108          $next_prune = time() + ($prune_freq * 86400);
 2109   
 2110          prune($forum_id, $prune_mode, $prune_date, $prune_flags, true);
 2111   
 2112          $sql = 'UPDATE ' . FORUMS_TABLE . "
 2113              SET prune_next = $next_prune
 2114              WHERE forum_id = $forum_id";
 2115          $db->sql_query($sql);
 2116   
 2117          add_log('admin', 'LOG_AUTO_PRUNE', $row['forum_name']);
 2118      }
 2119   
 2120      return;
 2121  }
 2122   
 2123  /**
 2124  * remove_comments will strip the sql comment lines out of an uploaded sql file
 2125  * specifically for mssql and postgres type files in the install....
 2126  */
 2127  function remove_comments(&$output)
 2128  {
 2129      $lines = explode("\n", $output);
 2130      $output = '';
 2131   
 2132      // try to keep mem. use down
 2133      $linecount = sizeof($lines);
 2134   
 2135      $in_comment = false;
 2136      for ($i = 0; $i < $linecount; $i++)
 2137      {
 2138          if (trim($lines[$i]) == '/*')
 2139          {
 2140              $in_comment = true;
 2141          }
 2142   
 2143          if (!$in_comment)
 2144          {
 2145              $output .= $lines[$i] . "\n";
 2146          }
 2147   
 2148          if (trim($lines[$i]) == '*/')
 2149          {
 2150              $in_comment = false;
 2151          }
 2152      }
 2153   
 2154      unset($lines);
 2155      return $output;
 2156  }
 2157   
 2158  /**
 2159  * Cache moderators, called whenever permissions are changed via admin_permissions. Changes of username
 2160  * and group names must be carried through for the moderators table
 2161  */
 2162  function cache_moderators()
 2163  {
 2164      global $db, $cache, $auth, $phpbb_root_path, $phpEx;
 2165   
 2166      // Remove cached sql results
 2167      $cache->destroy('sql', MODERATOR_CACHE_TABLE);
 2168   
 2169      // Clear table
 2170      switch ($db->sql_layer)
 2171      {
 2172          case 'sqlite':
 2173          case 'firebird':
 2174              $db->sql_query('DELETE FROM ' . MODERATOR_CACHE_TABLE);
 2175          break;
 2176   
 2177          default:
 2178              $db->sql_query('TRUNCATE TABLE ' . MODERATOR_CACHE_TABLE);
 2179          break;
 2180      }
 2181   
 2182      // We add moderators who have forum moderator permissions without an explicit ACL_NEVER setting
 2183      $hold_ary = $ug_id_ary = $sql_ary = array();
 2184   
 2185      // Grab all users having moderative options...
 2186      $hold_ary = $auth->acl_user_raw_data(false, 'm_%', false);
 2187   
 2188      // Add users?
 2189      if (sizeof($hold_ary))
 2190      {
 2191          // At least one moderative option warrants a display
 2192          $ug_id_ary = array_keys($hold_ary);
 2193   
 2194          // Remove users who have group memberships with DENY moderator permissions
 2195          $sql = $db->sql_build_query('SELECT', array(
 2196              'SELECT'    => 'a.forum_id, ug.user_id',
 2197   
 2198              'FROM'        => array(
 2199                  ACL_OPTIONS_TABLE    => 'o',
 2200                  USER_GROUP_TABLE    => 'ug',
 2201                  ACL_GROUPS_TABLE    => 'a'
 2202              ),
 2203   
 2204              'LEFT_JOIN'    => array(
 2205                  array(
 2206                      'FROM'    => array(ACL_ROLES_DATA_TABLE => 'r'),
 2207                      'ON'    => 'a.auth_role_id = r.role_id'
 2208                  )
 2209              ),
 2210   
 2211              'WHERE'        => '(o.auth_option_id = a.auth_option_id OR o.auth_option_id = r.auth_option_id)
 2212                  AND ((a.auth_setting = ' . ACL_NEVER . ' AND r.auth_setting IS NULL)
 2213                      OR r.auth_setting = ' . ACL_NEVER . ')
 2214                  AND a.group_id = ug.group_id
 2215                  AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . "
 2216                  AND ug.user_pending = 0
 2217                  AND o.auth_option " . $db->sql_like_expression('m_' . $db->any_char),
 2218          ));
 2219          $result = $db->sql_query($sql);
 2220   
 2221          while ($row = $db->sql_fetchrow($result))
 2222          {
 2223              if (isset($hold_ary[$row['user_id']][$row['forum_id']]))
 2224              {
 2225                  unset($hold_ary[$row['user_id']][$row['forum_id']]);
 2226              }
 2227          }
 2228          $db->sql_freeresult($result);
 2229   
 2230          if (sizeof($hold_ary))
 2231          {
 2232              // Get usernames...
 2233              $sql = 'SELECT user_id, username
 2234                  FROM ' . USERS_TABLE . '
 2235                  WHERE ' . $db->sql_in_set('user_id', array_keys($hold_ary));
 2236              $result = $db->sql_query($sql);
 2237   
 2238              $usernames_ary = array();
 2239              while ($row = $db->sql_fetchrow($result))
 2240              {
 2241                  $usernames_ary[$row['user_id']] = $row['username'];
 2242              }
 2243   
 2244              foreach ($hold_ary as $user_id => $forum_id_ary)
 2245              {
 2246                  // Do not continue if user does not exist
 2247                  if (!isset($usernames_ary[$user_id]))
 2248                  {
 2249                      continue;
 2250                  }
 2251   
 2252                  foreach ($forum_id_ary as $forum_id => $auth_ary)
 2253                  {
 2254                      $sql_ary[] = array(
 2255                          'forum_id'        => (int) $forum_id,
 2256                          'user_id'        => (int) $user_id,
 2257                          'username'        => (string) $usernames_ary[$user_id],
 2258                          'group_id'        => 0,
 2259                          'group_name'    => ''
 2260                      );
 2261                  }
 2262              }
 2263          }
 2264      }
 2265   
 2266      // Now to the groups...
 2267      $hold_ary = $auth->acl_group_raw_data(false, 'm_%', false);
 2268   
 2269      if (sizeof($hold_ary))
 2270      {
 2271          $ug_id_ary = array_keys($hold_ary);
 2272   
 2273          // Make sure not hidden or special groups are involved...
 2274          $sql = 'SELECT group_name, group_id, group_type
 2275              FROM ' . GROUPS_TABLE . '
 2276              WHERE ' . $db->sql_in_set('group_id', $ug_id_ary);
 2277          $result = $db->sql_query($sql);
 2278   
 2279          $groupnames_ary = array();
 2280          while ($row = $db->sql_fetchrow($result))
 2281          {
 2282              if ($row['group_type'] == GROUP_HIDDEN || $row['group_type'] == GROUP_SPECIAL)
 2283              {
 2284                  unset($hold_ary[$row['group_id']]);
 2285              }
 2286   
 2287              $groupnames_ary[$row['group_id']] = $row['group_name'];
 2288          }
 2289          $db->sql_freeresult($result);
 2290   
 2291          foreach ($hold_ary as $group_id => $forum_id_ary)
 2292          {
 2293              // If there is no group, we do not assign it...
 2294              if (!isset($groupnames_ary[$group_id]))
 2295              {
 2296                  continue;
 2297              }
 2298   
 2299              foreach ($forum_id_ary as $forum_id => $auth_ary)
 2300              {
 2301                  $flag = false;
 2302                  foreach ($auth_ary as $auth_option => $setting)
 2303                  {
 2304                      // Make sure at least one ACL_YES option is set...
 2305                      if ($setting == ACL_YES)
 2306                      {
 2307                          $flag = true;
 2308                          break;
 2309                      }
 2310                  }
 2311   
 2312                  if (!$flag)
 2313                  {
 2314                      continue;
 2315                  }
 2316   
 2317                  $sql_ary[] = array(
 2318                      'forum_id'        => (int) $forum_id,
 2319                      'user_id'        => 0,
 2320                      'username'        => '',
 2321                      'group_id'        => (int) $group_id,
 2322                      'group_name'    => (string) $groupnames_ary[$group_id]
 2323                  );
 2324              }
 2325          }
 2326      }
 2327   
 2328      $db->sql_multi_insert(MODERATOR_CACHE_TABLE, $sql_ary);
 2329  }
 2330   
 2331  /**
 2332  * View log
 2333  */
 2334  function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC')
 2335  {
 2336      global $db, $user, $auth, $phpEx, $phpbb_root_path, $phpbb_admin_path;
 2337   
 2338      $topic_id_list = $reportee_id_list = $is_auth = $is_mod = array();
 2339   
 2340      $profile_url = (defined('IN_ADMIN')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=overview') : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile');
 2341   
 2342      switch ($mode)
 2343      {
 2344          case 'admin':
 2345              $log_type = LOG_ADMIN;
 2346              $sql_forum = '';
 2347          break;
 2348   
 2349          case 'mod':
 2350              $log_type = LOG_MOD;
 2351   
 2352              if ($topic_id)
 2353              {
 2354                  $sql_forum = 'AND l.topic_id = ' . intval($topic_id);
 2355              }
 2356              else if (is_array($forum_id))
 2357              {
 2358                  $sql_forum = 'AND ' . $db->sql_in_set('l.forum_id', array_map('intval', $forum_id));
 2359              }
 2360              else
 2361              {
 2362                  $sql_forum = ($forum_id) ? 'AND l.forum_id = ' . intval($forum_id) : '';
 2363              }
 2364          break;
 2365   
 2366          case 'user':
 2367              $log_type = LOG_USERS;
 2368              $sql_forum = 'AND l.reportee_id = ' . (int) $user_id;
 2369          break;
 2370          
 2371          case 'users':
 2372              $log_type = LOG_USERS;
 2373              $sql_forum = '';
 2374          break;
 2375   
 2376          case 'critical':
 2377              $log_type = LOG_CRITICAL;
 2378              $sql_forum = '';
 2379          break;
 2380          
 2381          default:
 2382              return;
 2383      }
 2384   
 2385      $sql = "SELECT l.*, u.username, u.username_clean, u.user_colour
 2386          FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u
 2387          WHERE l.log_type = $log_type
 2388              AND u.user_id = l.user_id
 2389              " . (($limit_days) ? "AND l.log_time >= $limit_days" : '') . "
 2390              $sql_forum
 2391          ORDER BY $sort_by";
 2392      $result = $db->sql_query_limit($sql, $limit, $offset);
 2393   
 2394      $i = 0;
 2395      $log = array();
 2396      while ($row = $db->sql_fetchrow($result))
 2397      {
 2398          if ($row['topic_id'])
 2399          {
 2400              $topic_id_list[] = $row['topic_id'];
 2401          }
 2402   
 2403          if ($row['reportee_id'])
 2404          {
 2405              $reportee_id_list[] = $row['reportee_id'];
 2406          }
 2407   
 2408          $log[$i] = array(
 2409              'id'                => $row['log_id'],
 2410   
 2411              'reportee_id'            => $row['reportee_id'],
 2412              'reportee_username'        => '',
 2413              'reportee_username_full'=> '',
 2414   
 2415              'user_id'            => $row['user_id'],
 2416              'username'            => $row['username'],
 2417              'username_full'        => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
 2418   
 2419              'ip'                => $row['log_ip'],
 2420              'time'                => $row['log_time'],
 2421              'forum_id'            => $row['forum_id'],
 2422              'topic_id'            => $row['topic_id'],
 2423   
 2424              'viewforum'            => ($row['forum_id'] && $auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : false,
 2425              'action'            => (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
 2426          );
 2427   
 2428          if (!empty($row['log_data']))
 2429          {
 2430              $log_data_ary = unserialize($row['log_data']);
 2431   
 2432              if (isset($user->lang[$row['log_operation']]))
 2433              {
 2434                  // We supress the warning about inappropriate number of passed parameters here due to possible changes within LOG strings from one version to another.
 2435                  $log[$i]['action'] = @vsprintf($log[$i]['action'], $log_data_ary);
 2436   
 2437                  // If within the admin panel we do not censor text out
 2438                  if (defined('IN_ADMIN'))
 2439                  {
 2440                      $log[$i]['action'] = bbcode_nl2br($log[$i]['action']);
 2441                  }
 2442                  else
 2443                  {
 2444                      $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action']));
 2445                  }
 2446              }
 2447              else
 2448              {
 2449                  $log[$i]['action'] .= '<br />' . implode('', $log_data_ary);
 2450              }
 2451   
 2452              /* Apply make_clickable... has to be seen if it is for good. :/
 2453              // Seems to be not for the moment, reconsider later...
 2454              $log[$i]['action'] = make_clickable($log[$i]['action']);
 2455              */
 2456          }
 2457   
 2458          $i++;
 2459      }
 2460      $db->sql_freeresult($result);
 2461   
 2462      if (sizeof($topic_id_list))
 2463      {
 2464          $topic_id_list = array_unique($topic_id_list);
 2465   
 2466          // This query is not really needed if move_topics() updates the forum_id field,
 2467          // although it's also used to determine if the topic still exists in the database
 2468          $sql = 'SELECT topic_id, forum_id
 2469              FROM ' . TOPICS_TABLE . '
 2470              WHERE ' . $db->sql_in_set('topic_id', array_map('intval', $topic_id_list));
 2471          $result = $db->sql_query($sql);
 2472   
 2473          $default_forum_id = 0;
 2474   
 2475          while ($row = $db->sql_fetchrow($result))
 2476          {
 2477              if (!$row['forum_id'])
 2478              {
 2479                  if ($auth->acl_getf_global('f_read'))
 2480                  {
 2481                      if (!$default_forum_id)
 2482                      {
 2483                          $sql = 'SELECT forum_id
 2484                              FROM ' . FORUMS_TABLE . '
 2485                              WHERE forum_type = ' . FORUM_POST;
 2486                          $f_result = $db->sql_query_limit($sql, 1);
 2487                          $default_forum_id = (int) $db->sql_fetchfield('forum_id', false, $f_result);
 2488                          $db->sql_freeresult($f_result);
 2489                      }
 2490   
 2491                      $is_auth[$row['topic_id']] = $default_forum_id;
 2492                  }
 2493              }
 2494              else
 2495              {
 2496                  if ($auth->acl_get('f_read', $row['forum_id']))
 2497                  {
 2498                      $is_auth[$row['topic_id']] = $row['forum_id'];
 2499                  }
 2500              }
 2501   
 2502              if ($auth->acl_gets('a_', 'm_', $row['forum_id']))
 2503              {
 2504                  $is_mod[$row['topic_id']] = $row['forum_id'];
 2505              }
 2506          }
 2507          $db->sql_freeresult($result);
 2508   
 2509          foreach ($log as $key => $row)
 2510          {
 2511              $log[$key]['viewtopic'] = (isset($is_auth[$row['topic_id']])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $is_auth[$row['topic_id']] . '&amp;t=' . $row['topic_id']) : false;
 2512              $log[$key]['viewlogs'] = (isset($is_mod[$row['topic_id']])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=logs&amp;mode=topic_logs&amp;t=' . $row['topic_id'], true, $user->session_id) : false;
 2513          }
 2514      }
 2515   
 2516      if (sizeof($reportee_id_list))
 2517      {
 2518          $reportee_id_list = array_unique($reportee_id_list);
 2519          $reportee_names_list = array();
 2520   
 2521          $sql = 'SELECT user_id, username, user_colour
 2522              FROM ' . USERS_TABLE . '
 2523              WHERE ' . $db->sql_in_set('user_id', $reportee_id_list);
 2524          $result = $db->sql_query($sql);
 2525   
 2526          while ($row = $db->sql_fetchrow($result))
 2527          {
 2528              $reportee_names_list[$row['user_id']] = $row;
 2529          }
 2530          $db->sql_freeresult($result);
 2531   
 2532          foreach ($log as $key => $row)
 2533          {
 2534              if (!isset($reportee_names_list[$row['reportee_id']]))
 2535              {
 2536                  continue;
 2537              }
 2538   
 2539              $log[$key]['reportee_username'] = $reportee_names_list[$row['reportee_id']]['username'];
 2540              $log[$key]['reportee_username_full'] = get_username_string('full', $row['reportee_id'], $reportee_names_list[$row['reportee_id']]['username'], $reportee_names_list[$row['reportee_id']]['user_colour'], false, $profile_url);
 2541          }
 2542      }
 2543   
 2544      $sql = 'SELECT COUNT(l.log_id) AS total_entries
 2545          FROM ' . LOG_TABLE . " l
 2546          WHERE l.log_type = $log_type
 2547              AND l.log_time >= $limit_days
 2548              $sql_forum";
 2549      $result = $db->sql_query($sql);
 2550      $log_count = (int) $db->sql_fetchfield('total_entries');
 2551      $db->sql_freeresult($result);
 2552   
 2553      return;
 2554  }
 2555   
 2556  /**
 2557  * Update foes - remove moderators and administrators from foe lists...
 2558  */
 2559  function update_foes($group_id = false, $user_id = false)
 2560  {
 2561      global $db, $auth;
 2562   
 2563      // update foes for some user
 2564      if (is_array($user_id) && sizeof($user_id))
 2565      {
 2566          $sql = 'DELETE FROM ' . ZEBRA_TABLE . '
 2567              WHERE ' . $db->sql_in_set('zebra_id', $user_id) . '
 2568                  AND foe = 1';
 2569          $db->sql_query($sql);
 2570          return;
 2571      }
 2572   
 2573      // update foes for some group
 2574      if (is_array($group_id) && sizeof($group_id))
 2575      {
 2576          // Grab group settings...
 2577          $sql = $db->sql_build_query('SELECT', array(
 2578              'SELECT'    => 'a.group_id',
 2579   
 2580              'FROM'        => array(
 2581                  ACL_OPTIONS_TABLE    => 'ao',
 2582                  ACL_GROUPS_TABLE    => 'a'
 2583              ),
 2584   
 2585              'LEFT_JOIN'    => array(
 2586                  array(
 2587                      'FROM'    => array(ACL_ROLES_DATA_TABLE => 'r'),
 2588                      'ON'    => 'a.auth_role_id = r.role_id'
 2589                  ),
 2590              ),
 2591   
 2592              'WHERE'        => '(ao.auth_option_id = a.auth_option_id OR ao.auth_option_id = r.auth_option_id)
 2593                  AND ' . $db->sql_in_set('a.group_id', $group_id) . "
 2594                  AND ao.auth_option IN ('a_', 'm_')",
 2595   
 2596              'GROUP_BY'    => 'a.group_id'
 2597          ));
 2598          $result = $db->sql_query($sql);
 2599   
 2600          $groups = array();
 2601          while ($row = $db->sql_fetchrow($result))
 2602          {
 2603              $groups[] = (int) $row['group_id'];
 2604          }
 2605          $db->sql_freeresult($result);
 2606   
 2607          if (!sizeof($groups))
 2608          {
 2609              return;
 2610          }
 2611   
 2612          switch ($db->sql_layer)
 2613          {
 2614              case 'mysqli':
 2615              case 'mysql4':
 2616                  $sql = 'DELETE ' . (($db->sql_layer === 'mysqli' || version_compare($db->mysql_version, '4.1', '>=')) ? 'z.*' : ZEBRA_TABLE) . '
 2617                      FROM ' . ZEBRA_TABLE . ' z, ' . USER_GROUP_TABLE . ' ug
 2618                      WHERE z.zebra_id = ug.user_id
 2619                          AND z.foe = 1
 2620                          AND ' . $db->sql_in_set('ug.group_id', $groups);
 2621                  $db->sql_query($sql);
 2622              break;
 2623   
 2624              default:
 2625                  $sql = 'SELECT user_id
 2626                      FROM ' . USER_GROUP_TABLE . '
 2627                      WHERE ' . $db->sql_in_set('group_id', $groups);
 2628                  $result = $db->sql_query($sql);
 2629   
 2630                  $users = array();
 2631                  while ($row = $db->sql_fetchrow($result))
 2632                  {
 2633                      $users[] = (int) $row['user_id'];
 2634                  }
 2635                  $db->sql_freeresult($result);
 2636   
 2637                  if (sizeof($users))
 2638                  {                
 2639                      $sql = 'DELETE FROM ' . ZEBRA_TABLE . '
 2640                          WHERE ' . $db->sql_in_set('zebra_id', $users) . '
 2641                              AND foe = 1';
 2642                      $db->sql_query($sql);
 2643                  }
 2644              break;
 2645          }
 2646   
 2647          return;
 2648      }
 2649   
 2650      // update foes for everyone
 2651      $perms = array();
 2652      foreach ($auth->acl_get_list(false, array('a_', 'm_'), false) as $forum_id => $forum_ary)
 2653      {
 2654          foreach ($forum_ary as $auth_option => $user_ary)
 2655          {
 2656              $perms = array_merge($perms, $user_ary);
 2657          }
 2658      }
 2659   
 2660      if (sizeof($perms))
 2661      {
 2662          $sql = 'DELETE FROM ' . ZEBRA_TABLE . '
 2663              WHERE ' . $db->sql_in_set('zebra_id', array_unique($perms)) . '
 2664                  AND foe = 1';
 2665          $db->sql_query($sql);
 2666      }
 2667      unset($perms);
 2668  }
 2669   
 2670  /**
 2671  * Lists inactive users
 2672  */
 2673  function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_inactive_time DESC')
 2674  {
 2675      global $db, $user;
 2676   
 2677      $sql = 'SELECT COUNT(user_id) AS user_count
 2678          FROM ' . USERS_TABLE . '
 2679          WHERE user_type = ' . USER_INACTIVE .
 2680          (($limit_days) ? " AND user_inactive_time >= $limit_days" : '');
 2681      $result = $db->sql_query($sql);
 2682      $user_count = (int) $db->sql_fetchfield('user_count');
 2683      $db->sql_freeresult($result);
 2684   
 2685      if ($offset >= $user_count)
 2686      {
 2687          $offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
 2688      }
 2689   
 2690      $sql = 'SELECT user_id, username, user_regdate, user_lastvisit, user_inactive_time, user_inactive_reason
 2691          FROM ' . USERS_TABLE . '
 2692          WHERE user_type = ' . USER_INACTIVE .
 2693          (($limit_days) ? " AND user_inactive_time >= $limit_days" : '') . "
 2694          ORDER BY $sort_by";
 2695      $result = $db->sql_query_limit($sql, $limit, $offset);
 2696   
 2697      while ($row = $db->sql_fetchrow($result))
 2698      {
 2699          $row['inactive_reason'] = $user->lang['INACTIVE_REASON_UNKNOWN'];
 2700          switch ($row['user_inactive_reason'])
 2701          {
 2702              case INACTIVE_REGISTER:
 2703                  $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REGISTER'];
 2704              break;
 2705   
 2706              case INACTIVE_PROFILE:
 2707                  $row['inactive_reason'] = $user->lang['INACTIVE_REASON_PROFILE'];
 2708              break;
 2709   
 2710              case INACTIVE_MANUAL:
 2711                  $row['inactive_reason'] = $user->lang['INACTIVE_REASON_MANUAL'];
 2712              break;
 2713   
 2714              case INACTIVE_REMIND:
 2715                  $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REMIND'];
 2716              break;
 2717          }
 2718      
 2719          $users[] = $row;
 2720      }
 2721   
 2722      return $offset;
 2723  }
 2724   
 2725  /**
 2726  * Lists warned users
 2727  */
 2728  function view_warned_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_warnings DESC')
 2729  {
 2730      global $db;
 2731   
 2732      $sql = 'SELECT user_id, username, user_colour, user_warnings, user_last_warning
 2733          FROM ' . USERS_TABLE . '
 2734          WHERE user_warnings > 0
 2735          ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '') . "
 2736          ORDER BY $sort_by";
 2737      $result = $db->sql_query_limit($sql, $limit, $offset);
 2738      $users = $db->sql_fetchrowset($result);
 2739      $db->sql_freeresult($result);
 2740   
 2741      $sql = 'SELECT count(user_id) AS user_count
 2742          FROM ' . USERS_TABLE . '
 2743          WHERE user_warnings > 0
 2744          ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '');
 2745      $result = $db->sql_query($sql);
 2746      $user_count = (int) $db->sql_fetchfield('user_count');
 2747      $db->sql_freeresult($result);
 2748   
 2749      return;
 2750  }
 2751   
 2752  /**
 2753  * Get database size
 2754  * Currently only mysql and mssql are supported
 2755  */
 2756  function get_database_size()
 2757  {
 2758      global $db, $user, $table_prefix;
 2759   
 2760      $database_size = false;
 2761   
 2762      // This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0
 2763      switch ($db->sql_layer)
 2764      {
 2765          case 'mysql':
 2766          case 'mysql4':
 2767          case 'mysqli':
 2768              $sql = 'SELECT VERSION() AS mysql_version';
 2769              $result = $db->sql_query($sql);
 2770              $row = $db->sql_fetchrow($result);
 2771              $db->sql_freeresult($result);
 2772   
 2773              if ($row)
 2774              {
 2775                  $version = $row['mysql_version'];
 2776   
 2777                  if (preg_match('#(3\.23|[45]\.)#', $version))
 2778                  {
 2779                      $db_name = (preg_match('#^(?:3\.23\.(?:[6-9]|[1-9]{2}))|[45]\.#', $version)) ? "`{$db->dbname}`" : $db->dbname;
 2780   
 2781                      $sql = 'SHOW TABLE STATUS
 2782                          FROM ' . $db_name;
 2783                      $result = $db->sql_query($sql, 7200);
 2784   
 2785                      $database_size = 0;
 2786                      while ($row = $db->sql_fetchrow($result))
 2787                      {
 2788                          if ((isset($row['Type']) && $row['Type'] != 'MRG_MyISAM') || (isset($row['Engine']) && ($row['Engine'] == 'MyISAM' || $row['Engine'] == 'InnoDB')))
 2789                          {
 2790                              if ($table_prefix != '')
 2791                              {
 2792                                  if (strpos($row['Name'], $table_prefix) !== false)
 2793                                  {
 2794                                      $database_size += $row['Data_length'] + $row['Index_length'];
 2795                                  }
 2796                              }
 2797                              else
 2798                              {
 2799                                  $database_size += $row['Data_length'] + $row['Index_length'];
 2800                              }
 2801                          }
 2802                      }
 2803                      $db->sql_freeresult($result);
 2804                  }
 2805              }
 2806          break;
 2807   
 2808          case 'firebird':
 2809              global $dbname;
 2810   
 2811              // if it on the local machine, we can get lucky
 2812              if (file_exists($dbname))
 2813              {
 2814                  $database_size = filesize($dbname);
 2815              }
 2816   
 2817          break;
 2818   
 2819          case 'sqlite':
 2820              global $dbhost;
 2821   
 2822              if (file_exists($dbhost))
 2823              {
 2824                  $database_size = filesize($dbhost);
 2825              }
 2826   
 2827          break;
 2828   
 2829          case 'mssql':
 2830          case 'mssql_odbc':
 2831              $sql = 'SELECT ((SUM(size) * 8.0) * 1024.0) as dbsize
 2832                  FROM sysfiles';
 2833              $result = $db->sql_query($sql, 7200);
 2834              $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false;
 2835              $db->sql_freeresult($result);
 2836          break;
 2837   
 2838          case 'postgres':
 2839              $sql = "SELECT proname
 2840                  FROM pg_proc
 2841                  WHERE proname = 'pg_database_size'";
 2842              $result = $db->sql_query($sql);
 2843              $row = $db->sql_fetchrow($result);
 2844              $db->sql_freeresult($result);
 2845   
 2846              if ($row['proname'] == 'pg_database_size')
 2847              {
 2848                  $database = $db->dbname;
 2849                  if (strpos($database, '.') !== false)
 2850                  {
 2851                      list($database, ) = explode('.', $database);
 2852                  }
 2853   
 2854                  $sql = "SELECT oid
 2855                      FROM pg_database
 2856                      WHERE datname = '$database'";
 2857                  $result = $db->sql_query($sql);
 2858                  $row = $db->sql_fetchrow($result);
 2859                  $db->sql_freeresult($result);
 2860   
 2861                  $oid = $row['oid'];
 2862   
 2863                  $sql = 'SELECT pg_database_size(' . $oid . ') as size';
 2864                  $result = $db->sql_query($sql);
 2865                  $row = $db->sql_fetchrow($result);
 2866                  $db->sql_freeresult($result);
 2867   
 2868                  $database_size = $row['size'];
 2869              }
 2870          break;
 2871   
 2872          case 'oracle':
 2873              $sql = 'SELECT SUM(bytes) as dbsize
 2874                  FROM user_segments';
 2875              $result = $db->sql_query($sql, 7200);
 2876              $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false;
 2877              $db->sql_freeresult($result);
 2878          break;
 2879      }
 2880   
 2881      if ($database_size !== false)
 2882      {
 2883          $database_size = ($database_size >= 1048576) ? sprintf('%.2f ' . $user->lang['MB'], ($database_size / 1048576)) : (($database_size >= 1024) ? sprintf('%.2f ' . $user->lang['KB'], ($database_size / 1024)) : sprintf('%.2f ' . $user->lang['BYTES'], $database_size));
 2884      }
 2885      else
 2886      {
 2887          $database_size = $user->lang['NOT_AVAILABLE'];
 2888      }
 2889   
 2890      return $database_size;
 2891  }
 2892   
 2893  /**
 2894  * Retrieve contents from remotely stored file
 2895  */
 2896  function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port = 80, $timeout = 10)
 2897  {
 2898      global $user;
 2899   
 2900      if ($fsock = @fsockopen($host, $port, $errno, $errstr, $timeout))
 2901      {
 2902          @fputs($fsock, "GET $directory/$filename HTTP/1.1\r\n");
 2903          @fputs($fsock, "HOST: $host\r\n");
 2904          @fputs($fsock, "Connection: close\r\n\r\n");
 2905      
 2906          $file_info = '';
 2907          $get_info = false;
 2908   
 2909          while (!@feof($fsock))
 2910          {
 2911              if ($get_info)
 2912              {
 2913                  $file_info .= @fread($fsock, 1024);
 2914              }
 2915              else
 2916              {
 2917                  $line = @fgets($fsock, 1024);
 2918                  if ($line == "\r\n")
 2919                  {
 2920                      $get_info = true;
 2921                  }
 2922                  else if (stripos($line, '404 not found') !== false)
 2923                  {
 2924                      $errstr = $user->lang['FILE_NOT_FOUND'] . ': ' . $filename;
 2925                      return false;
 2926                  }
 2927              }
 2928          }
 2929          @fclose($fsock);
 2930      }
 2931      else
 2932      {
 2933          if ($errstr)
 2934          {
 2935              $errstr = utf8_convert_message($errstr);
 2936              return false;
 2937          }
 2938          else
 2939          {
 2940              $errstr = $user->lang['FSOCK_DISABLED'];
 2941              return false;
 2942          }
 2943      }
 2944      
 2945      return $file_info;
 2946  }
 2947   
 2948  /**
 2949  * Tidy Warnings
 2950  * Remove all warnings which have now expired from the database
 2951  * The duration of a warning can be defined by the administrator
 2952  * This only removes the warning and reduces the associated count,
 2953  * it does not remove the user note recording the contents of the warning
 2954  */
 2955  function tidy_warnings()
 2956  {
 2957      global $db, $config;
 2958   
 2959      $expire_date = time() - ($config['warnings_expire_days'] * 86400);
 2960      $warning_list = $user_list = array();
 2961   
 2962      $sql = 'SELECT * FROM ' . WARNINGS_TABLE . "
 2963          WHERE warning_time < $expire_date";
 2964      $result = $db->sql_query($sql);
 2965   
 2966      while ($row = $db->sql_fetchrow($result))
 2967      {
 2968          $warning_list[] = $row['warning_id'];
 2969          $user_list[$row['user_id']] = isset($user_list[$row['user_id']]) ? ++$user_list[$row['user_id']] : 1;
 2970      }
 2971      $db->sql_freeresult($result);
 2972   
 2973      if (sizeof($warning_list))
 2974      {
 2975          $db->sql_transaction('begin');
 2976   
 2977          $sql = 'DELETE FROM ' . WARNINGS_TABLE . '
 2978              WHERE ' . $db->sql_in_set('warning_id', $warning_list);
 2979          $db->sql_query($sql);
 2980      
 2981          foreach ($user_list as $user_id => $value)
 2982          {
 2983              $sql = 'UPDATE ' . USERS_TABLE . " SET user_warnings = user_warnings - $value
 2984                  WHERE user_id = $user_id";
 2985              $db->sql_query($sql);
 2986          }
 2987   
 2988          $db->sql_transaction('commit');
 2989      }
 2990   
 2991      set_config('warnings_last_gc', time(), true);
 2992  }
 2993   
 2994  /**
 2995  * Tidy database, doing some maintanance tasks
 2996  */
 2997  function tidy_database()
 2998  {
 2999      global $db;
 3000   
 3001      set_config('database_last_gc', time(), true);
 3002  }
 3003   
 3004  /**
 3005  * Add permission language - this will make sure custom files will be included
 3006  */
 3007  function add_permission_language()
 3008  {
 3009      global $user, $phpEx;
 3010   
 3011      // First of all, our own file. We need to include it as the first file because it presets all relevant variables.
 3012      $user->add_lang('acp/permissions_phpbb');
 3013   
 3014      $files_to_add = array();
 3015   
 3016      // Now search in acp and mods folder for permissions_ files.
 3017      foreach (array('acp/', 'mods/') as $path)
 3018      {
 3019          $dh = @opendir($user->lang_path . $path);
 3020   
 3021          if ($dh)
 3022          {
 3023              while (($file = readdir($dh)) !== false)
 3024              {
 3025                  if ($file !== 'permissions_phpbb.' . $phpEx && strpos($file, 'permissions_') === 0 && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx)
 3026                  {
 3027                      $files_to_add[] = $path . substr($file, 0, -(strlen($phpEx) + 1));
 3028                  }
 3029              }
 3030              closedir($dh);
 3031          }
 3032      }
 3033   
 3034      if (!sizeof($files_to_add))
 3035      {
 3036          return false;
 3037      }
 3038   
 3039      $user->add_lang($files_to_add);
 3040      return true;
 3041  }
 3042   
 3043  ?>