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  ?>