[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/includes/ -> functions_admin.php (source)

   1  <?php
   2  /**
   3  *
   4  * @package acp
   5  * @version $Id$
   6  * @copyright (c) 2005 phpBB Group
   7  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
   8  *
   9  */
  10  
  11  /**
  12  * @ignore
  13  */
  14  if (!defined('IN_PHPBB'))
  15  {
  16      exit;
  17  }
  18  
  19  /**
  20  * Recalculate Nested Sets
  21  *
  22  * @param int    $new_id    first left_id (should start with 1)
  23  * @param string    $pkey    primary key-column (containing the id for the parent_id of the children)
  24  * @param string    $table    constant or fullname of the table
  25  * @param int    $parent_id parent_id of the current set (default = 0)
  26  * @param array    $where    contains strings to compare closer on the where statement (additional)
  27  *
  28  * @author EXreaction
  29  */
  30  function recalc_nested_sets(&$new_id, $pkey, $table, $parent_id = 0, $where = array())
  31  {
  32      global $db;
  33  
  34      $sql = 'SELECT *
  35          FROM ' . $table . '
  36          WHERE parent_id = ' . (int) $parent_id .
  37          ((!empty($where)) ? ' AND ' . implode(' AND ', $where) : '') . '
  38          ORDER BY left_id ASC';
  39      $result = $db->sql_query($sql);
  40      while ($row = $db->sql_fetchrow($result))
  41      {
  42          // First we update the left_id for this module
  43          if ($row['left_id'] != $new_id)
  44          {
  45              $db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('left_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}");
  46          }
  47          $new_id++;
  48  
  49          // Then we go through any children and update their left/right id's
  50          recalc_nested_sets($new_id, $pkey, $table, $row[$pkey], $where);
  51  
  52          // Then we come back and update the right_id for this module
  53          if ($row['right_id'] != $new_id)
  54          {
  55              $db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('right_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}");
  56          }
  57          $new_id++;
  58      }
  59      $db->sql_freeresult($result);
  60  }
  61  
  62  /**
  63  * Simple version of jumpbox, just lists authed forums
  64  */
  65  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)
  66  {
  67      global $db, $user, $auth;
  68  
  69      // This query is identical to the jumpbox one
  70      $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, forum_flags, forum_options, left_id, right_id
  71          FROM ' . FORUMS_TABLE . '
  72          ORDER BY left_id ASC';
  73      $result = $db->sql_query($sql, 600);
  74  
  75      $right = 0;
  76      $padding_store = array('0' => '');
  77      $padding = '';
  78      $forum_list = ($return_array) ? array() : '';
  79  
  80      // Sometimes it could happen that forums will be displayed here not be displayed within the index page
  81      // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions.
  82      // If this happens, the padding could be "broken"
  83  
  84      while ($row = $db->sql_fetchrow($result))
  85      {
  86          if ($row['left_id'] < $right)
  87          {
  88              $padding .= '&nbsp; &nbsp;';
  89              $padding_store[$row['parent_id']] = $padding;
  90          }
  91          else if ($row['left_id'] > $right + 1)
  92          {
  93              $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : '';
  94          }
  95  
  96          $right = $row['right_id'];
  97          $disabled = false;
  98  
  99          if (!$ignore_acl && $auth->acl_gets(array('f_list', 'a_forum', 'a_forumadd', 'a_forumdel'), $row['forum_id']))
 100          {
 101              if ($only_acl_post && !$auth->acl_get('f_post', $row['forum_id']) || (!$auth->acl_get('m_approve', $row['forum_id']) && !$auth->acl_get('f_noapprove', $row['forum_id'])))
 102              {
 103                  $disabled = true;
 104              }
 105          }
 106          else if (!$ignore_acl)
 107          {
 108              continue;
 109          }
 110  
 111          if (
 112              ((is_array($ignore_id) && in_array($row['forum_id'], $ignore_id)) || $row['forum_id'] == $ignore_id)
 113              ||
 114              // Non-postable forum with no subforums, don't display
 115              ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']) && $ignore_emptycat)
 116              ||
 117              ($row['forum_type'] != FORUM_POST && $ignore_nonpost)
 118              )
 119          {
 120              $disabled = true;
 121          }
 122  
 123          if ($return_array)
 124          {
 125              // Include some more information...
 126              $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? true : false) : (($row['forum_id'] == $select_id) ? true : false);
 127              $forum_list[$row['forum_id']] = array_merge(array('padding' => $padding, 'selected' => ($selected && !$disabled), 'disabled' => $disabled), $row);
 128          }
 129          else
 130          {
 131              $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? ' selected="selected"' : '') : (($row['forum_id'] == $select_id) ? ' selected="selected"' : '');
 132              $forum_list .= '<option value="' . $row['forum_id'] . '"' . (($disabled) ? ' disabled="disabled" class="disabled-option"' : $selected) . '>' . $padding . $row['forum_name'] . '</option>';
 133          }
 134      }
 135      $db->sql_freeresult($result);
 136      unset($padding_store);
 137  
 138      return $forum_list;
 139  }
 140  
 141  /**
 142  * Generate size select options
 143  */
 144  function size_select_options($size_compare)
 145  {
 146      global $user;
 147  
 148      $size_types_text = array($user->lang['BYTES'], $user->lang['KIB'], $user->lang['MIB']);
 149      $size_types = array('b', 'kb', 'mb');
 150  
 151      $s_size_options = '';
 152  
 153      for ($i = 0, $size = sizeof($size_types_text); $i < $size; $i++)
 154      {
 155          $selected = ($size_compare == $size_types[$i]) ? ' selected="selected"' : '';
 156          $s_size_options .= '<option value="' . $size_types[$i] . '"' . $selected . '>' . $size_types_text[$i] . '</option>';
 157      }
 158  
 159      return $s_size_options;
 160  }
 161  
 162  /**
 163  * Generate list of groups (option fields without select)
 164  *
 165  * @param int $group_id The default group id to mark as selected
 166  * @param array $exclude_ids The group ids to exclude from the list, false (default) if you whish to exclude no id
 167  * @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.
 168  *
 169  * @return string The list of options.
 170  */
 171  function group_select_options($group_id, $exclude_ids = false, $manage_founder = false)
 172  {
 173      global $db, $user, $config;
 174  
 175      $exclude_sql = ($exclude_ids !== false && sizeof($exclude_ids)) ? 'WHERE ' . $db->sql_in_set('group_id', array_map('intval', $exclude_ids), true) : '';
 176      $sql_and = (!$config['coppa_enable']) ? (($exclude_sql) ? ' AND ' : ' WHERE ') . "group_name <> 'REGISTERED_COPPA'" : '';
 177      $sql_founder = ($manage_founder !== false) ? (($exclude_sql || $sql_and) ? ' AND ' : ' WHERE ') . 'group_founder_manage = ' . (int) $manage_founder : '';
 178  
 179      $sql = 'SELECT group_id, group_name, group_type
 180          FROM ' . GROUPS_TABLE . "
 181          $exclude_sql
 182          $sql_and
 183          $sql_founder
 184          ORDER BY group_type DESC, group_name ASC";
 185      $result = $db->sql_query($sql);
 186  
 187      $s_group_options = '';
 188      while ($row = $db->sql_fetchrow($result))
 189      {
 190          $selected = ($row['group_id'] == $group_id) ? ' selected="selected"' : '';
 191          $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>';
 192      }
 193      $db->sql_freeresult($result);
 194  
 195      return $s_group_options;
 196  }
 197  
 198  /**
 199  * Obtain authed forums list
 200  */
 201  function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only = false, $no_cache = false)
 202  {
 203      global $db, $auth;
 204      static $forum_rows;
 205  
 206      if (!isset($forum_rows))
 207      {
 208          // This query is identical to the jumpbox one
 209          $expire_time = ($no_cache) ? 0 : 600;
 210  
 211          $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id
 212              FROM ' . FORUMS_TABLE . '
 213              ORDER BY left_id ASC';
 214          $result = $db->sql_query($sql, $expire_time);
 215  
 216          $forum_rows = array();
 217  
 218          $right = $padding = 0;
 219          $padding_store = array('0' => 0);
 220  
 221          while ($row = $db->sql_fetchrow($result))
 222          {
 223              if ($row['left_id'] < $right)
 224              {
 225                  $padding++;
 226                  $padding_store[$row['parent_id']] = $padding;
 227              }
 228              else if ($row['left_id'] > $right + 1)
 229              {
 230                  // Ok, if the $padding_store for this parent is empty there is something wrong. For now we will skip over it.
 231                  // @todo digging deep to find out "how" this can happen.
 232                  $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding;
 233              }
 234  
 235              $right = $row['right_id'];
 236              $row['padding'] = $padding;
 237  
 238              $forum_rows[] = $row;
 239          }
 240          $db->sql_freeresult($result);
 241          unset($padding_store);
 242      }
 243  
 244      $rowset = array();
 245      foreach ($forum_rows as $row)
 246      {
 247          if ($postable_only && $row['forum_type'] != FORUM_POST)
 248          {
 249              continue;
 250          }
 251  
 252          if ($acl_list == '' || ($acl_list != '' && $auth->acl_gets($acl_list, $row['forum_id'])))
 253          {
 254              $rowset[] = ($id_only) ? (int) $row['forum_id'] : $row;
 255          }
 256      }
 257  
 258      return $rowset;
 259  }
 260  
 261  /**
 262  * Get forum branch
 263  */
 264  function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $include_forum = true)
 265  {
 266      global $db;
 267  
 268      switch ($type)
 269      {
 270          case 'parents':
 271              $condition = 'f1.left_id BETWEEN f2.left_id AND f2.right_id';
 272          break;
 273  
 274          case 'children':
 275              $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id';
 276          break;
 277  
 278          default:
 279              $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id OR f1.left_id BETWEEN f2.left_id AND f2.right_id';
 280          break;
 281      }
 282  
 283      $rows = array();
 284  
 285      $sql = 'SELECT f2.*
 286          FROM ' . FORUMS_TABLE . ' f1
 287          LEFT JOIN ' . FORUMS_TABLE . " f2 ON ($condition)
 288          WHERE f1.forum_id = $forum_id
 289          ORDER BY f2.left_id " . (($order == 'descending') ? 'ASC' : 'DESC');
 290      $result = $db->sql_query($sql);
 291  
 292      while ($row = $db->sql_fetchrow($result))
 293      {
 294          if (!$include_forum && $row['forum_id'] == $forum_id)
 295          {
 296              continue;
 297          }
 298  
 299          $rows[] = $row;
 300      }
 301      $db->sql_freeresult($result);
 302  
 303      return $rows;
 304  }
 305  
 306  /**
 307  * Copies permissions from one forum to others
 308  *
 309  * @param int    $src_forum_id        The source forum we want to copy permissions from
 310  * @param array    $dest_forum_ids        The destination forum(s) we want to copy to
 311  * @param bool    $clear_dest_perms    True if destination permissions should be deleted
 312  * @param bool    $add_log            True if log entry should be added
 313  *
 314  * @return bool                        False on error
 315  *
 316  * @author bantu
 317  */
 318  function copy_forum_permissions($src_forum_id, $dest_forum_ids, $clear_dest_perms = true, $add_log = true)
 319  {
 320      global $db;
 321  
 322      // Only one forum id specified
 323      if (!is_array($dest_forum_ids))
 324      {
 325          $dest_forum_ids = array($dest_forum_ids);
 326      }
 327  
 328      // Make sure forum ids are integers
 329      $src_forum_id = (int) $src_forum_id;
 330      $dest_forum_ids = array_map('intval', $dest_forum_ids);
 331  
 332      // No source forum or no destination forums specified
 333      if (empty($src_forum_id) || empty($dest_forum_ids))
 334      {
 335          return false;
 336      }
 337  
 338      // Check if source forum exists
 339      $sql = 'SELECT forum_name
 340          FROM ' . FORUMS_TABLE . '
 341          WHERE forum_id = ' . $src_forum_id;
 342      $result = $db->sql_query($sql);
 343      $src_forum_name = $db->sql_fetchfield('forum_name');
 344      $db->sql_freeresult($result);
 345  
 346      // Source forum doesn't exist
 347      if (empty($src_forum_name))
 348      {
 349          return false;
 350      }
 351  
 352      // Check if destination forums exists
 353      $sql = 'SELECT forum_id, forum_name
 354          FROM ' . FORUMS_TABLE . '
 355          WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids);
 356      $result = $db->sql_query($sql);
 357  
 358      $dest_forum_ids = $dest_forum_names = array();
 359      while ($row = $db->sql_fetchrow($result))
 360      {
 361          $dest_forum_ids[]    = (int) $row['forum_id'];
 362          $dest_forum_names[]    = $row['forum_name'];
 363      }
 364      $db->sql_freeresult($result);
 365  
 366      // No destination forum exists
 367      if (empty($dest_forum_ids))
 368      {
 369          return false;
 370      }
 371  
 372      // From the mysql documentation:
 373      // Prior to MySQL 4.0.14, the target table of the INSERT statement cannot appear
 374      // in the FROM clause of the SELECT part of the query. This limitation is lifted in 4.0.14.
 375      // Due to this we stay on the safe side if we do the insertion "the manual way"
 376  
 377      // Rowsets we're going to insert
 378      $users_sql_ary = $groups_sql_ary = array();
 379  
 380      // Query acl users table for source forum data
 381      $sql = 'SELECT user_id, auth_option_id, auth_role_id, auth_setting
 382          FROM ' . ACL_USERS_TABLE . '
 383          WHERE forum_id = ' . $src_forum_id;
 384      $result = $db->sql_query($sql);
 385  
 386      while ($row = $db->sql_fetchrow($result))
 387      {
 388          $row = array(
 389              'user_id'            => (int) $row['user_id'],
 390              'auth_option_id'    => (int) $row['auth_option_id'],
 391              'auth_role_id'        => (int) $row['auth_role_id'],
 392              'auth_setting'        => (int) $row['auth_setting'],
 393          );
 394  
 395          foreach ($dest_forum_ids as $dest_forum_id)
 396          {
 397              $users_sql_ary[] = $row + array('forum_id' => $dest_forum_id);
 398          }
 399      }
 400      $db->sql_freeresult($result);
 401  
 402      // Query acl groups table for source forum data
 403      $sql = 'SELECT group_id, auth_option_id, auth_role_id, auth_setting
 404          FROM ' . ACL_GROUPS_TABLE . '
 405          WHERE forum_id = ' . $src_forum_id;
 406      $result = $db->sql_query($sql);
 407  
 408      while ($row = $db->sql_fetchrow($result))
 409      {
 410          $row = array(
 411              'group_id'            => (int) $row['group_id'],
 412              'auth_option_id'    => (int) $row['auth_option_id'],
 413              'auth_role_id'        => (int) $row['auth_role_id'],
 414              'auth_setting'        => (int) $row['auth_setting'],
 415          );
 416  
 417          foreach ($dest_forum_ids as $dest_forum_id)
 418          {
 419              $groups_sql_ary[] = $row + array('forum_id' => $dest_forum_id);
 420          }
 421      }
 422      $db->sql_freeresult($result);
 423  
 424      $db->sql_transaction('begin');
 425  
 426      // Clear current permissions of destination forums
 427      if ($clear_dest_perms)
 428      {
 429          $sql = 'DELETE FROM ' . ACL_USERS_TABLE . '
 430              WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids);
 431          $db->sql_query($sql);
 432  
 433          $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . '
 434              WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids);
 435          $db->sql_query($sql);
 436      }
 437  
 438      $db->sql_multi_insert(ACL_USERS_TABLE, $users_sql_ary);
 439      $db->sql_multi_insert(ACL_GROUPS_TABLE, $groups_sql_ary);
 440  
 441      if ($add_log)
 442      {
 443          add_log('admin', 'LOG_FORUM_COPIED_PERMISSIONS', $src_forum_name, implode(', ', $dest_forum_names));
 444      }
 445  
 446      $db->sql_transaction('commit');
 447  
 448      return true;
 449  }
 450  
 451  /**
 452  * Get physical file listing
 453  */
 454  function filelist($rootdir, $dir = '', $type = 'gif|jpg|jpeg|png')
 455  {
 456      $matches = array($dir => array());
 457  
 458      // Remove initial / if present
 459      $rootdir = (substr($rootdir, 0, 1) == '/') ? substr($rootdir, 1) : $rootdir;
 460      // Add closing / if not present
 461      $rootdir = ($rootdir && substr($rootdir, -1) != '/') ? $rootdir . '/' : $rootdir;
 462  
 463      // Remove initial / if present
 464      $dir = (substr($dir, 0, 1) == '/') ? substr($dir, 1) : $dir;
 465      // Add closing / if not present
 466      $dir = ($dir && substr($dir, -1) != '/') ? $dir . '/' : $dir;
 467  
 468      if (!is_dir($rootdir . $dir))
 469      {
 470          return $matches;
 471      }
 472  
 473      $dh = @opendir($rootdir . $dir);
 474  
 475      if (!$dh)
 476      {
 477          return $matches;
 478      }
 479  
 480      while (($fname = readdir($dh)) !== false)
 481      {
 482          if (is_file("$rootdir$dir$fname"))
 483          {
 484              if (filesize("$rootdir$dir$fname") && preg_match('#\.' . $type . '$#i', $fname))
 485              {
 486                  $matches[$dir][] = $fname;
 487              }
 488          }
 489          else if ($fname[0] != '.' && is_dir("$rootdir$dir$fname"))
 490          {
 491              $matches += filelist($rootdir, "$dir$fname", $type);
 492          }
 493      }
 494      closedir($dh);
 495  
 496      return $matches;
 497  }
 498  
 499  /**
 500  * Move topic(s)
 501  */
 502  function move_topics($topic_ids, $forum_id, $auto_sync = true)
 503  {
 504      global $db;
 505  
 506      if (empty($topic_ids))
 507      {
 508          return;
 509      }
 510  
 511      $forum_ids = array($forum_id);
 512  
 513      if (!is_array($topic_ids))
 514      {
 515          $topic_ids = array($topic_ids);
 516      }
 517  
 518      $sql = 'DELETE FROM ' . TOPICS_TABLE . '
 519          WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids) . '
 520              AND forum_id = ' . $forum_id;
 521      $db->sql_query($sql);
 522  
 523      if ($auto_sync)
 524      {
 525          $sql = 'SELECT DISTINCT forum_id
 526              FROM ' . TOPICS_TABLE . '
 527              WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
 528          $result = $db->sql_query($sql);
 529  
 530          while ($row = $db->sql_fetchrow($result))
 531          {
 532              $forum_ids[] = $row['forum_id'];
 533          }
 534          $db->sql_freeresult($result);
 535      }
 536  
 537      $table_ary = array(TOPICS_TABLE, POSTS_TABLE, LOG_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE);
 538      foreach ($table_ary as $table)
 539      {
 540          $sql = "UPDATE $table
 541              SET forum_id = $forum_id
 542              WHERE " . $db->sql_in_set('topic_id', $topic_ids);
 543          $db->sql_query($sql);
 544      }
 545      unset($table_ary);
 546  
 547      if ($auto_sync)
 548      {
 549          sync('forum', 'forum_id', $forum_ids, true, true);
 550          unset($forum_ids);
 551      }
 552  }
 553  
 554  /**
 555  * Move post(s)
 556  */
 557  function move_posts($post_ids, $topic_id, $auto_sync = true)
 558  {
 559      global $db;
 560  
 561      if (!is_array($post_ids))
 562      {
 563          $post_ids = array($post_ids);
 564      }
 565  
 566      $forum_ids = array();
 567      $topic_ids = array($topic_id);
 568  
 569      $sql = 'SELECT DISTINCT topic_id, forum_id
 570          FROM ' . POSTS_TABLE . '
 571          WHERE ' . $db->sql_in_set('post_id', $post_ids);
 572      $result = $db->sql_query($sql);
 573  
 574      while ($row = $db->sql_fetchrow($result))
 575      {
 576          $forum_ids[] = (int) $row['forum_id'];
 577          $topic_ids[] = (int) $row['topic_id'];
 578      }
 579      $db->sql_freeresult($result);
 580  
 581      $sql = 'SELECT forum_id
 582          FROM ' . TOPICS_TABLE . '
 583          WHERE topic_id = ' . $topic_id;
 584      $result = $db->sql_query($sql);
 585      $forum_row = $db->sql_fetchrow($result);
 586      $db->sql_freeresult($result);
 587  
 588      if (!$forum_row)
 589      {
 590          trigger_error('NO_TOPIC');
 591      }
 592  
 593      $sql = 'UPDATE ' . POSTS_TABLE . '
 594          SET forum_id = ' . (int) $forum_row['forum_id'] . ", topic_id = $topic_id
 595          WHERE " . $db->sql_in_set('post_id', $post_ids);
 596      $db->sql_query($sql);
 597  
 598      $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
 599          SET topic_id = $topic_id, in_message = 0
 600          WHERE " . $db->sql_in_set('post_msg_id', $post_ids);
 601      $db->sql_query($sql);
 602  
 603      if ($auto_sync)
 604      {
 605          $forum_ids[] = (int) $forum_row['forum_id'];
 606  
 607          sync('topic_reported', 'topic_id', $topic_ids);
 608          sync('topic_attachment', 'topic_id', $topic_ids);
 609          sync('topic', 'topic_id', $topic_ids, true);
 610          sync('forum', 'forum_id', $forum_ids, true, true);
 611      }
 612  
 613      // Update posted information
 614      update_posted_info($topic_ids);
 615  }
 616  
 617  /**
 618  * Remove topic(s)
 619  */
 620  function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_sync = true, $call_delete_posts = true)
 621  {
 622      global $db, $config;
 623  
 624      $approved_topics = 0;
 625      $forum_ids = $topic_ids = array();
 626  
 627      if ($where_type === 'range')
 628      {
 629          $where_clause = $where_ids;
 630      }
 631      else
 632      {
 633          $where_ids = (is_array($where_ids)) ? array_unique($where_ids) : array($where_ids);
 634  
 635          if (!sizeof($where_ids))
 636          {
 637              return array('topics' => 0, 'posts' => 0);
 638          }
 639  
 640          $where_clause = $db->sql_in_set($where_type, $where_ids);
 641      }
 642  
 643      // Making sure that delete_posts does not call delete_topics again...
 644      $return = array(
 645          'posts' => ($call_delete_posts) ? delete_posts($where_type, $where_ids, false, true, $post_count_sync, false) : 0,
 646      );
 647  
 648      $sql = 'SELECT topic_id, forum_id, topic_approved, topic_moved_id
 649          FROM ' . TOPICS_TABLE . '
 650          WHERE ' . $where_clause;
 651      $result = $db->sql_query($sql);
 652  
 653      while ($row = $db->sql_fetchrow($result))
 654      {
 655          $forum_ids[] = $row['forum_id'];
 656          $topic_ids[] = $row['topic_id'];
 657  
 658          if ($row['topic_approved'] && !$row['topic_moved_id'])
 659          {
 660              $approved_topics++;
 661          }
 662      }
 663      $db->sql_freeresult($result);
 664  
 665      $return['topics'] = sizeof($topic_ids);
 666  
 667      if (!sizeof($topic_ids))
 668      {
 669          return $return;
 670      }
 671  
 672      $db->sql_transaction('begin');
 673  
 674      $table_ary = array(BOOKMARKS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, POLL_VOTES_TABLE, POLL_OPTIONS_TABLE, TOPICS_WATCH_TABLE, TOPICS_TABLE);
 675  
 676      foreach ($table_ary as $table)
 677      {
 678          $sql = "DELETE FROM $table
 679              WHERE " . $db->sql_in_set('topic_id', $topic_ids);
 680          $db->sql_query($sql);
 681      }
 682      unset($table_ary);
 683  
 684      $moved_topic_ids = array();
 685  
 686      // update the other forums
 687      $sql = 'SELECT topic_id, forum_id
 688          FROM ' . TOPICS_TABLE . '
 689          WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids);
 690      $result = $db->sql_query($sql);
 691  
 692      while ($row = $db->sql_fetchrow($result))
 693      {
 694          $forum_ids[] = $row['forum_id'];
 695          $moved_topic_ids[] = $row['topic_id'];
 696      }
 697      $db->sql_freeresult($result);
 698  
 699      if (sizeof($moved_topic_ids))
 700      {
 701          $sql = 'DELETE FROM ' . TOPICS_TABLE . '
 702              WHERE ' . $db->sql_in_set('topic_id', $moved_topic_ids);
 703          $db->sql_query($sql);
 704      }
 705  
 706      $db->sql_transaction('commit');
 707  
 708      if ($auto_sync)
 709      {
 710          sync('forum', 'forum_id', array_unique($forum_ids), true, true);
 711          sync('topic_reported', $where_type, $where_ids);
 712      }
 713  
 714      if ($approved_topics)
 715      {
 716          set_config_count('num_topics', $approved_topics * (-1), true);
 717      }
 718  
 719      return $return;
 720  }
 721  
 722  /**
 723  * Remove post(s)
 724  */
 725  function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = true, $post_count_sync = true, $call_delete_topics = true)
 726  {
 727      global $db, $config, $phpbb_root_path, $phpEx;
 728  
 729      if ($where_type === 'range')
 730      {
 731          $where_clause = $where_ids;
 732      }
 733      else
 734      {
 735          if (is_array($where_ids))
 736          {
 737              $where_ids = array_unique($where_ids);
 738          }
 739          else
 740          {
 741              $where_ids = array($where_ids);
 742          }
 743  
 744          if (!sizeof($where_ids))
 745          {
 746              return false;
 747          }
 748  
 749          $where_ids = array_map('intval', $where_ids);
 750  
 751  /*        Possible code for splitting post deletion
 752          if (sizeof($where_ids) >= 1001)
 753          {
 754              // Split into chunks of 1000
 755              $chunks = array_chunk($where_ids, 1000);
 756  
 757              foreach ($chunks as $_where_ids)
 758              {
 759                  delete_posts($where_type, $_where_ids, $auto_sync, $posted_sync, $post_count_sync, $call_delete_topics);
 760              }
 761  
 762              return;
 763          }*/
 764  
 765          $where_clause = $db->sql_in_set($where_type, $where_ids);
 766      }
 767  
 768      $approved_posts = 0;
 769      $post_ids = $topic_ids = $forum_ids = $post_counts = $remove_topics = array();
 770  
 771      $sql = 'SELECT post_id, poster_id, post_approved, post_postcount, topic_id, forum_id
 772          FROM ' . POSTS_TABLE . '
 773          WHERE ' . $where_clause;
 774      $result = $db->sql_query($sql);
 775  
 776      while ($row = $db->sql_fetchrow($result))
 777      {
 778          $post_ids[] = (int) $row['post_id'];
 779          $poster_ids[] = (int) $row['poster_id'];
 780          $topic_ids[] = (int) $row['topic_id'];
 781          $forum_ids[] = (int) $row['forum_id'];
 782  
 783          if ($row['post_postcount'] && $post_count_sync && $row['post_approved'])
 784          {
 785              $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1;
 786          }
 787  
 788          if ($row['post_approved'])
 789          {
 790              $approved_posts++;
 791          }
 792      }
 793      $db->sql_freeresult($result);
 794  
 795      if (!sizeof($post_ids))
 796      {
 797          return false;
 798      }
 799  
 800      $db->sql_transaction('begin');
 801  
 802      $table_ary = array(POSTS_TABLE, REPORTS_TABLE);
 803  
 804      foreach ($table_ary as $table)
 805      {
 806          $sql = "DELETE FROM $table
 807              WHERE " . $db->sql_in_set('post_id', $post_ids);
 808          $db->sql_query($sql);
 809      }
 810      unset($table_ary);
 811  
 812      // Adjust users post counts
 813      if (sizeof($post_counts) && $post_count_sync)
 814      {
 815          foreach ($post_counts as $poster_id => $substract)
 816          {
 817              $sql = 'UPDATE ' . USERS_TABLE . '
 818                  SET user_posts = 0
 819                  WHERE user_id = ' . $poster_id . '
 820                  AND user_posts < ' . $substract;
 821              $db->sql_query($sql);
 822  
 823              $sql = 'UPDATE ' . USERS_TABLE . '
 824                  SET user_posts = user_posts - ' . $substract . '
 825                  WHERE user_id = ' . $poster_id . '
 826                  AND user_posts >= ' . $substract;
 827              $db->sql_query($sql);
 828          }
 829      }
 830  
 831      // Remove topics now having no posts?
 832      if (sizeof($topic_ids))
 833      {
 834          $sql = 'SELECT topic_id
 835              FROM ' . POSTS_TABLE . '
 836              WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
 837              GROUP BY topic_id';
 838          $result = $db->sql_query($sql);
 839  
 840          while ($row = $db->sql_fetchrow($result))
 841          {
 842              $remove_topics[] = $row['topic_id'];
 843          }
 844          $db->sql_freeresult($result);
 845  
 846          // Actually, those not within remove_topics should be removed. ;)
 847          $remove_topics = array_diff($topic_ids, $remove_topics);
 848      }
 849  
 850      // Remove the message from the search index
 851      $search_type = basename($config['search_type']);
 852  
 853      if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx))
 854      {
 855          trigger_error('NO_SUCH_SEARCH_MODULE');
 856      }
 857  
 858      include_once("{$phpbb_root_path}includes/search/$search_type.$phpEx");
 859  
 860      $error = false;
 861      $search = new $search_type($error);
 862  
 863      if ($error)
 864      {
 865          trigger_error($error);
 866      }
 867  
 868      $search->index_remove($post_ids, $poster_ids, $forum_ids);
 869  
 870      delete_attachments('post', $post_ids, false);
 871  
 872      $db->sql_transaction('commit');
 873  
 874      // Resync topics_posted table
 875      if ($posted_sync)
 876      {
 877          update_posted_info($topic_ids);
 878      }
 879  
 880      if ($auto_sync)
 881      {
 882          sync('topic_reported', 'topic_id', $topic_ids);
 883          sync('topic', 'topic_id', $topic_ids, true);
 884          sync('forum', 'forum_id', $forum_ids, true, true);
 885      }
 886  
 887      if ($approved_posts)
 888      {
 889          set_config_count('num_posts', $approved_posts * (-1), true);
 890      }
 891  
 892      // We actually remove topics now to not be inconsistent (the delete_topics function calls this function too)
 893      if (sizeof($remove_topics) && $call_delete_topics)
 894      {
 895          delete_topics('topic_id', $remove_topics, $auto_sync, $post_count_sync, false);
 896      }
 897  
 898      return sizeof($post_ids);
 899  }
 900  
 901  /**
 902  * Delete Attachments
 903  *
 904  * @param string $mode can be: post|message|topic|attach|user
 905  * @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
 906  * @param bool $resync set this to false if you are deleting posts or topics
 907  */
 908  function delete_attachments($mode, $ids, $resync = true)
 909  {
 910      global $db, $config;
 911  
 912      // 0 is as bad as an empty array
 913      if (empty($ids))
 914      {
 915          return false;
 916      }
 917  
 918      if (is_array($ids))
 919      {
 920          $ids = array_unique($ids);
 921          $ids = array_map('intval', $ids);
 922      }
 923      else
 924      {
 925          $ids = array((int) $ids);
 926      }
 927  
 928      $sql_where = '';
 929  
 930      switch ($mode)
 931      {
 932          case 'post':
 933          case 'message':
 934              $sql_id = 'post_msg_id';
 935              $sql_where = ' AND in_message = ' . ($mode == 'message' ? 1 : 0);
 936          break;
 937  
 938          case 'topic':
 939              $sql_id = 'topic_id';
 940          break;
 941  
 942          case 'user':
 943              $sql_id = 'poster_id';
 944          break;
 945  
 946          case 'attach':
 947          default:
 948              $sql_id = 'attach_id';
 949              $mode = 'attach';
 950          break;
 951      }
 952  
 953      $post_ids = $message_ids = $topic_ids = $physical = array();
 954  
 955      // Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
 956      $sql = 'SELECT post_msg_id, topic_id, in_message, physical_filename, thumbnail, filesize, is_orphan
 957              FROM ' . ATTACHMENTS_TABLE . '
 958              WHERE ' . $db->sql_in_set($sql_id, $ids);
 959  
 960      $sql .= $sql_where;
 961  
 962      $result = $db->sql_query($sql);
 963  
 964      while ($row = $db->sql_fetchrow($result))
 965      {
 966          // We only need to store post/message/topic ids if resync is enabled and the file is not orphaned
 967          if ($resync && !$row['is_orphan'])
 968          {
 969              if (!$row['in_message'])
 970              {
 971                  $post_ids[] = $row['post_msg_id'];
 972                  $topic_ids[] = $row['topic_id'];
 973              }
 974              else
 975              {
 976                  $message_ids[] = $row['post_msg_id'];
 977              }
 978          }
 979  
 980          $physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize'], 'is_orphan' => $row['is_orphan']);
 981      }
 982      $db->sql_freeresult($result);
 983  
 984      // Delete attachments
 985      $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
 986          WHERE ' . $db->sql_in_set($sql_id, $ids);
 987  
 988      $sql .= $sql_where;
 989  
 990      $db->sql_query($sql);
 991      $num_deleted = $db->sql_affectedrows();
 992  
 993      if (!$num_deleted)
 994      {
 995          return 0;
 996      }
 997  
 998      // Delete attachments from filesystem
 999      $space_removed = $files_removed = 0;
1000      foreach ($physical as $file_ary)
1001      {
1002          if (phpbb_unlink($file_ary['filename'], 'file', true) && !$file_ary['is_orphan'])
1003          {
1004              // Only non-orphaned files count to the file size
1005              $space_removed += $file_ary['filesize'];
1006              $files_removed++;
1007          }
1008  
1009          if ($file_ary['thumbnail'])
1010          {
1011              phpbb_unlink($file_ary['filename'], 'thumbnail', true);
1012          }
1013      }
1014  
1015      if ($space_removed || $files_removed)
1016      {
1017          set_config_count('upload_dir_size', $space_removed * (-1), true);
1018          set_config_count('num_files', $files_removed * (-1), true);
1019      }
1020  
1021      // If we do not resync, we do not need to adjust any message, post, topic or user entries
1022      if (!$resync)
1023      {
1024          return $num_deleted;
1025      }
1026  
1027      // No more use for the original ids
1028      unset($ids);
1029  
1030      // Now, we need to resync posts, messages, topics. We go through every one of them
1031      $post_ids = array_unique($post_ids);
1032      $message_ids = array_unique($message_ids);
1033      $topic_ids = array_unique($topic_ids);
1034  
1035      // Update post indicators for posts now no longer having attachments
1036      if (sizeof($post_ids))
1037      {
1038          // Just check which posts are still having an assigned attachment not orphaned by querying the attachments table
1039          $sql = 'SELECT post_msg_id
1040              FROM ' . ATTACHMENTS_TABLE . '
1041              WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
1042                  AND in_message = 0
1043                  AND is_orphan = 0';
1044          $result = $db->sql_query($sql);
1045  
1046          $remaining_ids = array();
1047          while ($row = $db->sql_fetchrow($result))
1048          {
1049              $remaining_ids[] = $row['post_msg_id'];
1050          }
1051          $db->sql_freeresult($result);
1052  
1053          // Now only unset those ids remaining
1054          $post_ids = array_diff($post_ids, $remaining_ids);
1055  
1056          if (sizeof($post_ids))
1057          {
1058              $sql = 'UPDATE ' . POSTS_TABLE . '
1059                  SET post_attachment = 0
1060                  WHERE ' . $db->sql_in_set('post_id', $post_ids);
1061              $db->sql_query($sql);
1062          }
1063      }
1064  
1065      // Update message table if messages are affected
1066      if (sizeof($message_ids))
1067      {
1068          // Just check which messages are still having an assigned attachment not orphaned by querying the attachments table
1069          $sql = 'SELECT post_msg_id
1070              FROM ' . ATTACHMENTS_TABLE . '
1071              WHERE ' . $db->sql_in_set('post_msg_id', $message_ids) . '
1072                  AND in_message = 1
1073                  AND is_orphan = 0';
1074          $result = $db->sql_query($sql);
1075  
1076          $remaining_ids = array();
1077          while ($row = $db->sql_fetchrow($result))
1078          {
1079              $remaining_ids[] = $row['post_msg_id'];
1080          }
1081          $db->sql_freeresult($result);
1082  
1083          // Now only unset those ids remaining
1084          $message_ids = array_diff($message_ids, $remaining_ids);
1085  
1086          if (sizeof($message_ids))
1087          {
1088              $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1089                  SET message_attachment = 0
1090                  WHERE ' . $db->sql_in_set('msg_id', $message_ids);
1091              $db->sql_query($sql);
1092          }
1093      }
1094  
1095      // Now update the topics. This is a bit trickier, because there could be posts still having attachments within the topic
1096      if (sizeof($topic_ids))
1097      {
1098          // Just check which topics are still having an assigned attachment not orphaned by querying the attachments table (much less entries expected)
1099          $sql = 'SELECT topic_id
1100              FROM ' . ATTACHMENTS_TABLE . '
1101              WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
1102                  AND is_orphan = 0';
1103          $result = $db->sql_query($sql);
1104  
1105          $remaining_ids = array();
1106          while ($row = $db->sql_fetchrow($result))
1107          {
1108              $remaining_ids[] = $row['topic_id'];
1109          }
1110          $db->sql_freeresult($result);
1111  
1112          // Now only unset those ids remaining
1113          $topic_ids = array_diff($topic_ids, $remaining_ids);
1114  
1115          if (sizeof($topic_ids))
1116          {
1117              $sql = 'UPDATE ' . TOPICS_TABLE . '
1118                  SET topic_attachment = 0
1119                  WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1120              $db->sql_query($sql);
1121          }
1122      }
1123  
1124      return $num_deleted;
1125  }
1126  
1127  /**
1128  * Deletes shadow topics pointing to a specified forum.
1129  *
1130  * @param int        $forum_id        The forum id
1131  * @param string        $sql_more        Additional WHERE statement, e.g. t.topic_time < (time() - 1234)
1132  * @param bool        $auto_sync        Will call sync() if this is true
1133  *
1134  * @return array        Array with affected forums
1135  *
1136  * @author bantu
1137  */
1138  function delete_topic_shadows($forum_id, $sql_more = '', $auto_sync = true)
1139  {
1140      global $db;
1141  
1142      if (!$forum_id)
1143      {
1144          // Nothing to do.
1145          return;
1146      }
1147  
1148      // Set of affected forums we have to resync
1149      $sync_forum_ids = array();
1150  
1151      // Amount of topics we select and delete at once.
1152      $batch_size = 500;
1153  
1154      do
1155      {
1156          $sql = 'SELECT t2.forum_id, t2.topic_id
1157              FROM ' . TOPICS_TABLE . ' t2, ' . TOPICS_TABLE . ' t
1158              WHERE t2.topic_moved_id = t.topic_id
1159                  AND t.forum_id = ' . (int) $forum_id . '
1160                  ' . (($sql_more) ? 'AND ' . $sql_more : '');
1161          $result = $db->sql_query_limit($sql, $batch_size);
1162  
1163          $topic_ids = array();
1164          while ($row = $db->sql_fetchrow($result))
1165          {
1166              $topic_ids[] = (int) $row['topic_id'];
1167  
1168              $sync_forum_ids[(int) $row['forum_id']] = (int) $row['forum_id'];
1169          }
1170          $db->sql_freeresult($result);
1171  
1172          if (!empty($topic_ids))
1173          {
1174              $sql = 'DELETE FROM ' . TOPICS_TABLE . '
1175                  WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1176              $db->sql_query($sql);
1177          }
1178      }
1179      while (sizeof($topic_ids) == $batch_size);
1180  
1181      if ($auto_sync)
1182      {
1183          sync('forum', 'forum_id', $sync_forum_ids, true, true);
1184      }
1185  
1186      return $sync_forum_ids;
1187  }
1188  
1189  /**
1190  * Update/Sync posted information for topics
1191  */
1192  function update_posted_info(&$topic_ids)
1193  {
1194      global $db, $config;
1195  
1196      if (empty($topic_ids) || !$config['load_db_track'])
1197      {
1198          return;
1199      }
1200  
1201      // First of all, let us remove any posted information for these topics
1202      $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . '
1203          WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1204      $db->sql_query($sql);
1205  
1206      // Now, let us collect the user/topic combos for rebuilding the information
1207      $sql = 'SELECT poster_id, topic_id
1208          FROM ' . POSTS_TABLE . '
1209          WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
1210              AND poster_id <> ' . ANONYMOUS . '
1211          GROUP BY poster_id, topic_id';
1212      $result = $db->sql_query($sql);
1213  
1214      $posted = array();
1215      while ($row = $db->sql_fetchrow($result))
1216      {
1217          // Add as key to make them unique (grouping by) and circumvent empty keys on array_unique
1218          $posted[$row['poster_id']][] = $row['topic_id'];
1219      }
1220      $db->sql_freeresult($result);
1221  
1222      // Now add the information...
1223      $sql_ary = array();
1224      foreach ($posted as $user_id => $topic_row)
1225      {
1226          foreach ($topic_row as $topic_id)
1227          {
1228              $sql_ary[] = array(
1229                  'user_id'        => (int) $user_id,
1230                  'topic_id'        => (int) $topic_id,
1231                  'topic_posted'    => 1,
1232              );
1233          }
1234      }
1235      unset($posted);
1236  
1237      $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary);
1238  }
1239  
1240  /**
1241  * Delete attached file
1242  */
1243  function phpbb_unlink($filename, $mode = 'file', $entry_removed = false)
1244  {
1245      global $db, $phpbb_root_path, $config;
1246  
1247      // Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
1248      $sql = 'SELECT COUNT(attach_id) AS num_entries
1249          FROM ' . ATTACHMENTS_TABLE . "
1250          WHERE physical_filename = '" . $db->sql_escape(utf8_basename($filename)) . "'";
1251      $result = $db->sql_query($sql);
1252      $num_entries = (int) $db->sql_fetchfield('num_entries');
1253      $db->sql_freeresult($result);
1254  
1255      // Do not remove file if at least one additional entry with the same name exist.
1256      if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1))
1257      {
1258          return false;
1259      }
1260  
1261      $filename = ($mode == 'thumbnail') ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename);
1262      return @unlink($phpbb_root_path . $config['upload_path'] . '/' . $filename);
1263  }
1264  
1265  /**
1266  * All-encompasing sync function
1267  *
1268  * Exaples:
1269  * <code>
1270  * sync('topic', 'topic_id', 123);            // resync topic #123
1271  * sync('topic', 'forum_id', array(2, 3));    // resync topics from forum #2 and #3
1272  * sync('topic');                            // resync all topics
1273  * sync('topic', 'range', 'topic_id BETWEEN 1 AND 60');    // resync a range of topics/forums (only available for 'topic' and 'forum' modes)
1274  * </code>
1275  *
1276  * Modes:
1277  * - forum                Resync complete forum
1278  * - topic                Resync topics
1279  * - topic_moved            Removes topic shadows that would be in the same forum as the topic they link to
1280  * - topic_approved        Resyncs the topic_approved flag according to the status of the first post
1281  * - post_reported        Resyncs the post_reported flag, relying on actual reports
1282  * - topic_reported        Resyncs the topic_reported flag, relying on post_reported flags
1283  * - post_attachement    Same as post_reported, but with attachment flags
1284  * - topic_attachement    Same as topic_reported, but with attachment flags
1285  */
1286  function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $sync_extra = false)
1287  {
1288      global $db;
1289  
1290      if (is_array($where_ids))
1291      {
1292          $where_ids = array_unique($where_ids);
1293          $where_ids = array_map('intval', $where_ids);
1294      }
1295      else if ($where_type != 'range')
1296      {
1297          $where_ids = ($where_ids) ? array((int) $where_ids) : array();
1298      }
1299  
1300      if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_approved' || $mode == 'topic_reported' || $mode == 'post_reported')
1301      {
1302          if (!$where_type)
1303          {
1304              $where_sql = '';
1305              $where_sql_and = 'WHERE';
1306          }
1307          else if ($where_type == 'range')
1308          {
1309              // Only check a range of topics/forums. For instance: 'topic_id BETWEEN 1 AND 60'
1310              $where_sql = 'WHERE (' . $mode[0] . ".$where_ids)";
1311              $where_sql_and = $where_sql . "\n\tAND";
1312          }
1313          else
1314          {
1315              // Do not sync the "global forum"
1316              $where_ids = array_diff($where_ids, array(0));
1317  
1318              if (!sizeof($where_ids))
1319              {
1320                  // Empty array with IDs. This means that we don't have any work to do. Just return.
1321                  return;
1322              }
1323  
1324              // Limit the topics/forums we are syncing, use specific topic/forum IDs.
1325              // $where_type contains the field for the where clause (forum_id, topic_id)
1326              $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids);
1327              $where_sql_and = $where_sql . "\n\tAND";
1328          }
1329      }
1330      else
1331      {
1332          if (!sizeof($where_ids))
1333          {
1334              return;
1335          }
1336  
1337          // $where_type contains the field for the where clause (forum_id, topic_id)
1338          $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids);
1339          $where_sql_and = $where_sql . "\n\tAND";
1340      }
1341  
1342      switch ($mode)
1343      {
1344          case 'topic_moved':
1345              $db->sql_transaction('begin');
1346              switch ($db->sql_layer)
1347              {
1348                  case 'mysql4':
1349                  case 'mysqli':
1350                      $sql = 'DELETE FROM ' . TOPICS_TABLE . '
1351                          USING ' . TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2
1352                          WHERE t1.topic_moved_id = t2.topic_id
1353                              AND t1.forum_id = t2.forum_id";
1354                      $db->sql_query($sql);
1355                  break;
1356  
1357                  default:
1358                      $sql = 'SELECT t1.topic_id
1359                          FROM ' .TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2
1360                          WHERE t1.topic_moved_id = t2.topic_id
1361                              AND t1.forum_id = t2.forum_id";
1362                      $result = $db->sql_query($sql);
1363  
1364                      $topic_id_ary = array();
1365                      while ($row = $db->sql_fetchrow($result))
1366                      {
1367                          $topic_id_ary[] = $row['topic_id'];
1368                      }
1369                      $db->sql_freeresult($result);
1370  
1371                      if (!sizeof($topic_id_ary))
1372                      {
1373                          return;
1374                      }
1375  
1376                      $sql = 'DELETE FROM ' . TOPICS_TABLE . '
1377                          WHERE ' . $db->sql_in_set('topic_id', $topic_id_ary);
1378                      $db->sql_query($sql);
1379  
1380                  break;
1381              }
1382  
1383              $db->sql_transaction('commit');
1384              break;
1385  
1386          case 'topic_approved':
1387  
1388              $db->sql_transaction('begin');
1389              switch ($db->sql_layer)
1390              {
1391                  case 'mysql4':
1392                  case 'mysqli':
1393                      $sql = 'UPDATE ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
1394                          SET t.topic_approved = p.post_approved
1395                          $where_sql_and t.topic_first_post_id = p.post_id";
1396                      $db->sql_query($sql);
1397                  break;
1398  
1399                  default:
1400                      $sql = 'SELECT t.topic_id, p.post_approved
1401                          FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
1402                          $where_sql_and p.post_id = t.topic_first_post_id
1403                              AND p.post_approved <> t.topic_approved";
1404                      $result = $db->sql_query($sql);
1405  
1406                      $topic_ids = array();
1407                      while ($row = $db->sql_fetchrow($result))
1408                      {
1409                          $topic_ids[] = $row['topic_id'];
1410                      }
1411                      $db->sql_freeresult($result);
1412  
1413                      if (!sizeof($topic_ids))
1414                      {
1415                          return;
1416                      }
1417  
1418                      $sql = 'UPDATE ' . TOPICS_TABLE . '
1419                          SET topic_approved = 1 - topic_approved
1420                          WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1421                      $db->sql_query($sql);
1422                  break;
1423              }
1424  
1425              $db->sql_transaction('commit');
1426              break;
1427  
1428          case 'post_reported':
1429              $post_ids = $post_reported = array();
1430  
1431              $db->sql_transaction('begin');
1432  
1433              $sql = 'SELECT p.post_id, p.post_reported
1434                  FROM ' . POSTS_TABLE . " p
1435                  $where_sql
1436                  GROUP BY p.post_id, p.post_reported";
1437              $result = $db->sql_query($sql);
1438  
1439              while ($row = $db->sql_fetchrow($result))
1440              {
1441                  $post_ids[$row['post_id']] = $row['post_id'];
1442                  if ($row['post_reported'])
1443                  {
1444                      $post_reported[$row['post_id']] = 1;
1445                  }
1446              }
1447              $db->sql_freeresult($result);
1448  
1449              $sql = 'SELECT DISTINCT(post_id)
1450                  FROM ' . REPORTS_TABLE . '
1451                  WHERE ' . $db->sql_in_set('post_id', $post_ids) . '
1452                      AND report_closed = 0';
1453              $result = $db->sql_query($sql);
1454  
1455              $post_ids = array();
1456              while ($row = $db->sql_fetchrow($result))
1457              {
1458                  if (!isset($post_reported[$row['post_id']]))
1459                  {
1460                      $post_ids[] = $row['post_id'];
1461                  }
1462                  else
1463                  {
1464                      unset($post_reported[$row['post_id']]);
1465                  }
1466              }
1467              $db->sql_freeresult($result);
1468  
1469              // $post_reported should be empty by now, if it's not it contains
1470              // posts that are falsely flagged as reported
1471              foreach ($post_reported as $post_id => $void)
1472              {
1473                  $post_ids[] = $post_id;
1474              }
1475  
1476              if (sizeof($post_ids))
1477              {
1478                  $sql = 'UPDATE ' . POSTS_TABLE . '
1479                      SET post_reported = 1 - post_reported
1480                      WHERE ' . $db->sql_in_set('post_id', $post_ids);
1481                  $db->sql_query($sql);
1482              }
1483  
1484              $db->sql_transaction('commit');
1485              break;
1486  
1487          case 'topic_reported':
1488              if ($sync_extra)
1489              {
1490                  sync('post_reported', $where_type, $where_ids);
1491              }
1492  
1493              $topic_ids = $topic_reported = array();
1494  
1495              $db->sql_transaction('begin');
1496  
1497              $sql = 'SELECT DISTINCT(t.topic_id)
1498                  FROM ' . POSTS_TABLE . " t
1499                  $where_sql_and t.post_reported = 1";
1500              $result = $db->sql_query($sql);
1501  
1502              while ($row = $db->sql_fetchrow($result))
1503              {
1504                  $topic_reported[$row['topic_id']] = 1;
1505              }
1506              $db->sql_freeresult($result);
1507  
1508              $sql = 'SELECT t.topic_id, t.topic_reported
1509                  FROM ' . TOPICS_TABLE . " t
1510                  $where_sql";
1511              $result = $db->sql_query($sql);
1512  
1513              while ($row = $db->sql_fetchrow($result))
1514              {
1515                  if ($row['topic_reported'] ^ isset($topic_reported[$row['topic_id']]))
1516                  {
1517                      $topic_ids[] = $row['topic_id'];
1518                  }
1519              }
1520              $db->sql_freeresult($result);
1521  
1522              if (sizeof($topic_ids))
1523              {
1524                  $sql = 'UPDATE ' . TOPICS_TABLE . '
1525                      SET topic_reported = 1 - topic_reported
1526                      WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1527                  $db->sql_query($sql);
1528              }
1529  
1530              $db->sql_transaction('commit');
1531              break;
1532  
1533          case 'post_attachment':
1534              $post_ids = $post_attachment = array();
1535  
1536              $db->sql_transaction('begin');
1537  
1538              $sql = 'SELECT p.post_id, p.post_attachment
1539                  FROM ' . POSTS_TABLE . " p
1540                  $where_sql
1541                  GROUP BY p.post_id, p.post_attachment";
1542              $result = $db->sql_query($sql);
1543  
1544              while ($row = $db->sql_fetchrow($result))
1545              {
1546                  $post_ids[$row['post_id']] = $row['post_id'];
1547                  if ($row['post_attachment'])
1548                  {
1549                      $post_attachment[$row['post_id']] = 1;
1550                  }
1551              }
1552              $db->sql_freeresult($result);
1553  
1554              $sql = 'SELECT DISTINCT(post_msg_id)
1555                  FROM ' . ATTACHMENTS_TABLE . '
1556                  WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
1557                      AND in_message = 0';
1558              $result = $db->sql_query($sql);
1559  
1560              $post_ids = array();
1561              while ($row = $db->sql_fetchrow($result))
1562              {
1563                  if (!isset($post_attachment[$row['post_msg_id']]))
1564                  {
1565                      $post_ids[] = $row['post_msg_id'];
1566                  }
1567                  else
1568                  {
1569                      unset($post_attachment[$row['post_msg_id']]);
1570                  }
1571              }
1572              $db->sql_freeresult($result);
1573  
1574              // $post_attachment should be empty by now, if it's not it contains
1575              // posts that are falsely flagged as having attachments
1576              foreach ($post_attachment as $post_id => $void)
1577              {
1578                  $post_ids[] = $post_id;
1579              }
1580  
1581              if (sizeof($post_ids))
1582              {
1583                  $sql = 'UPDATE ' . POSTS_TABLE . '
1584                      SET post_attachment = 1 - post_attachment
1585                      WHERE ' . $db->sql_in_set('post_id', $post_ids);
1586                  $db->sql_query($sql);
1587              }
1588  
1589              $db->sql_transaction('commit');
1590              break;
1591  
1592          case 'topic_attachment':
1593              if ($sync_extra)
1594              {
1595                  sync('post_attachment', $where_type, $where_ids);
1596              }
1597  
1598              $topic_ids = $topic_attachment = array();
1599  
1600              $db->sql_transaction('begin');
1601  
1602              $sql = 'SELECT DISTINCT(t.topic_id)
1603                  FROM ' . POSTS_TABLE . " t
1604                  $where_sql_and t.post_attachment = 1";
1605              $result = $db->sql_query($sql);
1606  
1607              while ($row = $db->sql_fetchrow($result))
1608              {
1609                  $topic_attachment[$row['topic_id']] = 1;
1610              }
1611              $db->sql_freeresult($result);
1612  
1613              $sql = 'SELECT t.topic_id, t.topic_attachment
1614                  FROM ' . TOPICS_TABLE . " t
1615                  $where_sql";
1616              $result = $db->sql_query($sql);
1617  
1618              while ($row = $db->sql_fetchrow($result))
1619              {
1620                  if ($row['topic_attachment'] ^ isset($topic_attachment[$row['topic_id']]))
1621                  {
1622                      $topic_ids[] = $row['topic_id'];
1623                  }
1624              }
1625              $db->sql_freeresult($result);
1626  
1627              if (sizeof($topic_ids))
1628              {
1629                  $sql = 'UPDATE ' . TOPICS_TABLE . '
1630                      SET topic_attachment = 1 - topic_attachment
1631                      WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1632                  $db->sql_query($sql);
1633              }
1634  
1635              $db->sql_transaction('commit');
1636  
1637              break;
1638  
1639          case 'forum':
1640  
1641              $db->sql_transaction('begin');
1642  
1643              // 1: Get the list of all forums
1644              $sql = 'SELECT f.*
1645                  FROM ' . FORUMS_TABLE . " f
1646                  $where_sql";
1647              $result = $db->sql_query($sql);
1648  
1649              $forum_data = $forum_ids = $post_ids = $last_post_id = $post_info = array();
1650              while ($row = $db->sql_fetchrow($result))
1651              {
1652                  if ($row['forum_type'] == FORUM_LINK)
1653                  {
1654                      continue;
1655                  }
1656  
1657                  $forum_id = (int) $row['forum_id'];
1658                  $forum_ids[$forum_id] = $forum_id;
1659  
1660                  $forum_data[$forum_id] = $row;
1661                  if ($sync_extra)
1662                  {
1663                      $forum_data[$forum_id]['posts'] = 0;
1664                      $forum_data[$forum_id]['topics'] = 0;
1665                      $forum_data[$forum_id]['topics_real'] = 0;
1666                  }
1667                  $forum_data[$forum_id]['last_post_id'] = 0;
1668                  $forum_data[$forum_id]['last_post_subject'] = '';
1669                  $forum_data[$forum_id]['last_post_time'] = 0;
1670                  $forum_data[$forum_id]['last_poster_id'] = 0;
1671                  $forum_data[$forum_id]['last_poster_name'] = '';
1672                  $forum_data[$forum_id]['last_poster_colour'] = '';
1673              }
1674              $db->sql_freeresult($result);
1675  
1676              if (!sizeof($forum_ids))
1677              {
1678                  break;
1679              }
1680  
1681              $forum_ids = array_values($forum_ids);
1682  
1683              // 2: Get topic counts for each forum (optional)
1684              if ($sync_extra)
1685              {
1686                  $sql = 'SELECT forum_id, topic_approved, COUNT(topic_id) AS forum_topics
1687                      FROM ' . TOPICS_TABLE . '
1688                      WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . '
1689                      GROUP BY forum_id, topic_approved';
1690                  $result = $db->sql_query($sql);
1691  
1692                  while ($row = $db->sql_fetchrow($result))
1693                  {
1694                      $forum_id = (int) $row['forum_id'];
1695                      $forum_data[$forum_id]['topics_real'] += $row['forum_topics'];
1696  
1697                      if ($row['topic_approved'])
1698                      {
1699                          $forum_data[$forum_id]['topics'] = $row['forum_topics'];
1700                      }
1701                  }
1702                  $db->sql_freeresult($result);
1703              }
1704  
1705              // 3: Get post count for each forum (optional)
1706              if ($sync_extra)
1707              {
1708                  if (sizeof($forum_ids) == 1)
1709                  {
1710                      $sql = 'SELECT SUM(t.topic_replies + 1) AS forum_posts
1711                          FROM ' . TOPICS_TABLE . ' t
1712                          WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
1713                              AND t.topic_approved = 1
1714                              AND t.topic_status <> ' . ITEM_MOVED;
1715                  }
1716                  else
1717                  {
1718                      $sql = 'SELECT t.forum_id, SUM(t.topic_replies + 1) AS forum_posts
1719                          FROM ' . TOPICS_TABLE . ' t
1720                          WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
1721                              AND t.topic_approved = 1
1722                              AND t.topic_status <> ' . ITEM_MOVED . '
1723                          GROUP BY t.forum_id';
1724                  }
1725  
1726                  $result = $db->sql_query($sql);
1727  
1728                  while ($row = $db->sql_fetchrow($result))
1729                  {
1730                      $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
1731  
1732                      $forum_data[$forum_id]['posts'] = (int) $row['forum_posts'];
1733                  }
1734                  $db->sql_freeresult($result);
1735              }
1736  
1737              // 4: Get last_post_id for each forum
1738              if (sizeof($forum_ids) == 1)
1739              {
1740                  $sql = 'SELECT MAX(t.topic_last_post_id) as last_post_id
1741                      FROM ' . TOPICS_TABLE . ' t
1742                      WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
1743                          AND t.topic_approved = 1';
1744              }
1745              else
1746              {
1747                  $sql = 'SELECT t.forum_id, MAX(t.topic_last_post_id) as last_post_id
1748                      FROM ' . TOPICS_TABLE . ' t
1749                      WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
1750                          AND t.topic_approved = 1
1751                      GROUP BY t.forum_id';
1752              }
1753  
1754              $result = $db->sql_query($sql);
1755  
1756              while ($row = $db->sql_fetchrow($result))
1757              {
1758                  $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
1759  
1760                  $forum_data[$forum_id]['last_post_id'] = (int) $row['last_post_id'];
1761  
1762                  $post_ids[] = $row['last_post_id'];
1763              }
1764              $db->sql_freeresult($result);
1765  
1766              // 5: Retrieve last_post infos
1767              if (sizeof($post_ids))
1768              {
1769                  $sql = 'SELECT p.post_id, p.poster_id, p.post_subject, p.post_time, p.post_username, u.username, u.user_colour
1770                      FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1771                      WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
1772                          AND p.poster_id = u.user_id';
1773                  $result = $db->sql_query($sql);
1774  
1775                  while ($row = $db->sql_fetchrow($result))
1776                  {
1777                      $post_info[$row['post_id']] = $row;
1778                  }
1779                  $db->sql_freeresult($result);
1780  
1781                  foreach ($forum_data as $forum_id => $data)
1782                  {
1783                      if ($data['last_post_id'])
1784                      {
1785                          if (isset($post_info[$data['last_post_id']]))
1786                          {
1787                              $forum_data[$forum_id]['last_post_subject'] = $post_info[$data['last_post_id']]['post_subject'];
1788                              $forum_data[$forum_id]['last_post_time'] = $post_info[$data['last_post_id']]['post_time'];
1789                              $forum_data[$forum_id]['last_poster_id'] = $post_info[$data['last_post_id']]['poster_id'];
1790                              $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'];
1791                              $forum_data[$forum_id]['last_poster_colour'] = $post_info[$data['last_post_id']]['user_colour'];
1792                          }
1793                          else
1794                          {
1795                              // For some reason we did not find the post in the db
1796                              $forum_data[$forum_id]['last_post_id'] = 0;
1797                              $forum_data[$forum_id]['last_post_subject'] = '';
1798                              $forum_data[$forum_id]['last_post_time'] = 0;
1799                              $forum_data[$forum_id]['last_poster_id'] = 0;
1800                              $forum_data[$forum_id]['last_poster_name'] = '';
1801                              $forum_data[$forum_id]['last_poster_colour'] = '';
1802                          }
1803                      }
1804                  }
1805                  unset($post_info);
1806              }
1807  
1808              // 6: Now do that thing
1809              $fieldnames = array('last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour');
1810  
1811              if ($sync_extra)
1812              {
1813                  array_push($fieldnames, 'posts', 'topics', 'topics_real');
1814              }
1815  
1816              foreach ($forum_data as $forum_id => $row)
1817              {
1818                  $sql_ary = array();
1819  
1820                  foreach ($fieldnames as $fieldname)
1821                  {
1822                      if ($row['forum_' . $fieldname] != $row[$fieldname])
1823                      {
1824                          if (preg_match('#(name|colour|subject)$#', $fieldname))
1825                          {
1826                              $sql_ary['forum_' . $fieldname] = (string) $row[$fieldname];
1827                          }
1828                          else
1829                          {
1830                              $sql_ary['forum_' . $fieldname] = (int) $row[$fieldname];
1831                          }
1832                      }
1833                  }
1834  
1835                  if (sizeof($sql_ary))
1836                  {
1837                      $sql = 'UPDATE ' . FORUMS_TABLE . '
1838                          SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
1839                          WHERE forum_id = ' . $forum_id;
1840                      $db->sql_query($sql);
1841                  }
1842              }
1843  
1844              $db->sql_transaction('commit');
1845              break;
1846  
1847          case 'topic':
1848              $topic_data = $post_ids = $approved_unapproved_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array();
1849  
1850              $db->sql_transaction('begin');
1851  
1852              $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
1853                  FROM ' . TOPICS_TABLE . " t
1854                  $where_sql";
1855              $result = $db->sql_query($sql);
1856  
1857              while ($row = $db->sql_fetchrow($result))
1858              {
1859                  if ($row['topic_moved_id'])
1860                  {
1861                      $moved_topics[] = $row['topic_id'];
1862                      continue;
1863                  }
1864  
1865                  $topic_id = (int) $row['topic_id'];
1866                  $topic_data[$topic_id] = $row;
1867                  $topic_data[$topic_id]['replies_real'] = -1;
1868                  $topic_data[$topic_id]['replies'] = 0;
1869                  $topic_data[$topic_id]['first_post_id'] = 0;
1870                  $topic_data[$topic_id]['last_post_id'] = 0;
1871                  unset($topic_data[$topic_id]['topic_id']);
1872  
1873                  // This array holds all topic_ids
1874                  $delete_topics[$topic_id] = '';
1875  
1876                  if ($sync_extra)
1877                  {
1878                      $topic_data[$topic_id]['reported'] = 0;
1879                      $topic_data[$topic_id]['attachment'] = 0;
1880                  }
1881              }
1882              $db->sql_freeresult($result);
1883  
1884              // Use "t" as table alias because of the $where_sql clause
1885              // NOTE: 't.post_approved' in the GROUP BY is causing a major slowdown.
1886              $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
1887                  FROM ' . POSTS_TABLE . " t
1888                  $where_sql
1889                  GROUP BY t.topic_id, t.post_approved";
1890              $result = $db->sql_query($sql);
1891  
1892              while ($row = $db->sql_fetchrow($result))
1893              {
1894                  $topic_id = (int) $row['topic_id'];
1895  
1896                  $row['first_post_id'] = (int) $row['first_post_id'];
1897                  $row['last_post_id'] = (int) $row['last_post_id'];
1898  
1899                  if (!isset($topic_data[$topic_id]))
1900                  {
1901                      // Hey, these posts come from a topic that does not exist
1902                      $delete_posts[$topic_id] = '';
1903                  }
1904                  else
1905                  {
1906                      // Unset the corresponding entry in $delete_topics
1907                      // When we'll be done, only topics with no posts will remain
1908                      unset($delete_topics[$topic_id]);
1909  
1910                      $topic_data[$topic_id]['replies_real'] += $row['total_posts'];
1911                      $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']);
1912  
1913                      if ($row['post_approved'] || !$topic_data[$topic_id]['last_post_id'])
1914                      {
1915                          $topic_data[$topic_id]['replies'] = $row['total_posts'] - 1;
1916                          $topic_data[$topic_id]['last_post_id'] = $row['last_post_id'];
1917                      }
1918                  }
1919              }
1920              $db->sql_freeresult($result);
1921  
1922              foreach ($topic_data as $topic_id => $row)
1923              {
1924                  $post_ids[] = $row['first_post_id'];
1925                  if ($row['first_post_id'] != $row['last_post_id'])
1926                  {
1927                      $post_ids[] = $row['last_post_id'];
1928                  }
1929              }
1930  
1931              // Now we delete empty topics and orphan posts
1932              if (sizeof($delete_posts))
1933              {
1934                  delete_posts('topic_id', array_keys($delete_posts), false);
1935                  unset($delete_posts);
1936              }
1937  
1938              if (!sizeof($topic_data))
1939              {
1940                  // If we get there, topic ids were invalid or topics did not contain any posts
1941                  delete_topics($where_type, $where_ids, true);
1942                  return;
1943              }
1944  
1945              if (sizeof($delete_topics))
1946              {
1947                  $delete_topic_ids = array();
1948                  foreach ($delete_topics as $topic_id => $void)
1949                  {
1950                      unset($topic_data[$topic_id]);
1951                      $delete_topic_ids[] = $topic_id;
1952                  }
1953  
1954                  delete_topics('topic_id', $delete_topic_ids, false);
1955                  unset($delete_topics, $delete_topic_ids);
1956              }
1957  
1958              $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
1959                  FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1960                  WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
1961                      AND u.user_id = p.poster_id';
1962              $result = $db->sql_query($sql);
1963  
1964              $post_ids = array();
1965              while ($row = $db->sql_fetchrow($result))
1966              {
1967                  $topic_id = intval($row['topic_id']);
1968  
1969                  if ($row['post_id'] == $topic_data[$topic_id]['first_post_id'])
1970                  {
1971                      if ($topic_data[$topic_id]['topic_approved'] != $row['post_approved'])
1972                      {
1973                          $approved_unapproved_ids[] = $topic_id;
1974                      }
1975                      $topic_data[$topic_id]['time'] = $row['post_time'];
1976                      $topic_data[$topic_id]['poster'] = $row['poster_id'];
1977                      $topic_data[$topic_id]['first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
1978                      $topic_data[$topic_id]['first_poster_colour'] = $row['user_colour'];
1979                  }
1980  
1981                  if ($row['post_id'] == $topic_data[$topic_id]['last_post_id'])
1982                  {
1983                      $topic_data[$topic_id]['last_poster_id'] = $row['poster_id'];
1984                      $topic_data[$topic_id]['last_post_subject'] = $row['post_subject'];
1985                      $topic_data[$topic_id]['last_post_time'] = $row['post_time'];
1986                      $topic_data[$topic_id]['last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
1987                      $topic_data[$topic_id]['last_poster_colour'] = $row['user_colour'];
1988                  }
1989              }
1990              $db->sql_freeresult($result);
1991  
1992              // Make sure shadow topics do link to existing topics
1993              if (sizeof($moved_topics))
1994              {
1995                  $delete_topics = array();
1996  
1997                  $sql = 'SELECT t1.topic_id, t1.topic_moved_id
1998                      FROM ' . TOPICS_TABLE . ' t1
1999                      LEFT JOIN ' . TOPICS_TABLE . ' t2 ON (t2.topic_id = t1.topic_moved_id)
2000                      WHERE ' . $db->sql_in_set('t1.topic_id', $moved_topics) . '
2001                          AND t2.topic_id IS NULL';
2002                  $result = $db->sql_query($sql);
2003  
2004                  while ($row = $db->sql_fetchrow($result))
2005                  {
2006                      $delete_topics[] = $row['topic_id'];
2007                  }
2008                  $db->sql_freeresult($result);
2009  
2010                  if (sizeof($delete_topics))
2011                  {
2012                      delete_topics('topic_id', $delete_topics, false);
2013                  }
2014                  unset($delete_topics);
2015  
2016                  // Make sure shadow topics having no last post data being updated (this only rarely happens...)
2017                  $sql = 'SELECT topic_id, topic_moved_id, topic_last_post_id, topic_first_post_id
2018                      FROM ' . TOPICS_TABLE . '
2019                      WHERE ' . $db->sql_in_set('topic_id', $moved_topics) . '
2020                          AND topic_last_post_time = 0';
2021                  $result = $db->sql_query($sql);
2022  
2023                  $shadow_topic_data = $post_ids = array();
2024                  while ($row = $db->sql_fetchrow($result))
2025                  {
2026                      $shadow_topic_data[$row['topic_moved_id']] = $row;
2027                      $post_ids[] = $row['topic_last_post_id'];
2028                      $post_ids[] = $row['topic_first_post_id'];
2029                  }
2030                  $db->sql_freeresult($result);
2031  
2032                  $sync_shadow_topics = array();
2033                  if (sizeof($post_ids))
2034                  {
2035                      $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
2036                          FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
2037                          WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
2038                              AND u.user_id = p.poster_id';
2039                      $result = $db->sql_query($sql);
2040  
2041                      $post_ids = array();
2042                      while ($row = $db->sql_fetchrow($result))
2043                      {
2044                          $topic_id = (int) $row['topic_id'];
2045  
2046                          // Ok, there should be a shadow topic. If there isn't, then there's something wrong with the db.
2047                          // However, there's not much we can do about it.
2048                          if (!empty($shadow_topic_data[$topic_id]))
2049                          {
2050                              if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_first_post_id'])
2051                              {
2052                                  $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id'];
2053  
2054                                  if (!isset($sync_shadow_topics[$orig_topic_id]))
2055                                  {
2056                                      $sync_shadow_topics[$orig_topic_id] = array();
2057                                  }
2058  
2059                                  $sync_shadow_topics[$orig_topic_id]['topic_time'] = $row['post_time'];
2060                                  $sync_shadow_topics[$orig_topic_id]['topic_poster'] = $row['poster_id'];
2061                                  $sync_shadow_topics[$orig_topic_id]['topic_first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
2062                                  $sync_shadow_topics[$orig_topic_id]['topic_first_poster_colour'] = $row['user_colour'];
2063                              }
2064  
2065                              if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_last_post_id'])
2066                              {
2067                                  $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id'];
2068  
2069                                  if (!isset($sync_shadow_topics[$orig_topic_id]))
2070                                  {
2071                                      $sync_shadow_topics[$orig_topic_id] = array();
2072                                  }
2073  
2074                                  $sync_shadow_topics[$orig_topic_id]['topic_last_poster_id'] = $row['poster_id'];
2075                                  $sync_shadow_topics[$orig_topic_id]['topic_last_post_subject'] = $row['post_subject'];
2076                                  $sync_shadow_topics[$orig_topic_id]['topic_last_post_time'] = $row['post_time'];
2077                                  $sync_shadow_topics[$orig_topic_id]['topic_last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
2078                                  $sync_shadow_topics[$orig_topic_id]['topic_last_poster_colour'] = $row['user_colour'];
2079                              }
2080                          }
2081                      }
2082                      $db->sql_freeresult($result);
2083  
2084                      $shadow_topic_data = array();
2085  
2086                      // Update the information we collected
2087                      if (sizeof($sync_shadow_topics))
2088                      {
2089                          foreach ($sync_shadow_topics as $sync_topic_id => $sql_ary)
2090                          {
2091                              $sql = 'UPDATE ' . TOPICS_TABLE . '
2092                                  SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
2093                                  WHERE topic_id = ' . $sync_topic_id;
2094                              $db->sql_query($sql);
2095                          }
2096                      }
2097                  }
2098  
2099                  unset($sync_shadow_topics, $shadow_topic_data);
2100              }
2101  
2102              // approved becomes unapproved, and vice-versa
2103              if (sizeof($approved_unapproved_ids))
2104              {
2105                  $sql = 'UPDATE ' . TOPICS_TABLE . '
2106                      SET topic_approved = 1 - topic_approved
2107                      WHERE ' . $db->sql_in_set('topic_id', $approved_unapproved_ids);
2108                  $db->sql_query($sql);
2109              }
2110              unset($approved_unapproved_ids);
2111  
2112              // These are fields that will be synchronised
2113              $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');
2114  
2115              if ($sync_extra)
2116              {
2117                  // This routine assumes that post_reported values are correct
2118                  // if they are not, use sync('post_reported') first
2119                  $sql = 'SELECT t.topic_id, p.post_id
2120                      FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
2121                      $where_sql_and p.topic_id = t.topic_id
2122                          AND p.post_reported = 1
2123                      GROUP BY t.topic_id, p.post_id";
2124                  $result = $db->sql_query($sql);
2125  
2126                  $fieldnames[] = 'reported';
2127                  while ($row = $db->sql_fetchrow($result))
2128                  {
2129                      $topic_data[intval($row['topic_id'])]['reported'] = 1;
2130                  }
2131                  $db->sql_freeresult($result);
2132  
2133                  // This routine assumes that post_attachment values are correct
2134                  // if they are not, use sync('post_attachment') first
2135                  $sql = 'SELECT t.topic_id, p.post_id
2136                      FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
2137                      $where_sql_and p.topic_id = t.topic_id
2138                          AND p.post_attachment = 1
2139                      GROUP BY t.topic_id, p.post_id";
2140                  $result = $db->sql_query($sql);
2141  
2142                  $fieldnames[] = 'attachment';
2143                  while ($row = $db->sql_fetchrow($result))
2144                  {
2145                      $topic_data[intval($row['topic_id'])]['attachment'] = 1;
2146                  }
2147                  $db->sql_freeresult($result);
2148              }
2149  
2150              foreach ($topic_data as $topic_id => $row)
2151              {
2152                  $sql_ary = array();
2153  
2154                  foreach ($fieldnames as $fieldname)
2155                  {
2156                      if (isset($row[$fieldname]) && isset($row['topic_' . $fieldname]) && $row['topic_' . $fieldname] != $row[$fieldname])
2157                      {
2158                          $sql_ary['topic_' . $fieldname] = $row[$fieldname];
2159                      }
2160                  }
2161  
2162                  if (sizeof($sql_ary))
2163                  {
2164                      $sql = 'UPDATE ' . TOPICS_TABLE . '
2165                          SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
2166                          WHERE topic_id = ' . $topic_id;
2167                      $db->sql_query($sql);
2168  
2169                      $resync_forums[$row['forum_id']] = $row['forum_id'];
2170                  }
2171              }
2172              unset($topic_data);
2173  
2174              $db->sql_transaction('commit');
2175  
2176              // if some topics have been resync'ed then resync parent forums
2177              // except when we're only syncing a range, we don't want to sync forums during
2178              // batch processing.
2179              if ($resync_parents && sizeof($resync_forums) && $where_type != 'range')
2180              {
2181                  sync('forum', 'forum_id', array_values($resync_forums), true, true);
2182              }
2183              break;
2184      }
2185  
2186      return;
2187  }
2188  
2189  /**
2190  * Prune function
2191  */
2192  function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync = true)
2193  {
2194      global $db;
2195  
2196      if (!is_array($forum_id))
2197      {
2198          $forum_id = array($forum_id);
2199      }
2200  
2201      if (!sizeof($forum_id))
2202      {
2203          return;
2204      }
2205  
2206      $sql_and = '';
2207  
2208      if (!($prune_flags & FORUM_FLAG_PRUNE_ANNOUNCE))
2209      {
2210          $sql_and .= ' AND topic_type <> ' . POST_ANNOUNCE;
2211      }
2212  
2213      if (!($prune_flags & FORUM_FLAG_PRUNE_STICKY))
2214      {
2215          $sql_and .= ' AND topic_type <> ' . POST_STICKY;
2216      }
2217  
2218      if ($prune_mode == 'posted')
2219      {
2220          $sql_and .= " AND topic_last_post_time < $prune_date";
2221      }
2222  
2223      if ($prune_mode == 'viewed')
2224      {
2225          $sql_and .= " AND topic_last_view_time < $prune_date";
2226      }
2227  
2228      $sql = 'SELECT topic_id
2229          FROM ' . TOPICS_TABLE . '
2230          WHERE ' . $db->sql_in_set('forum_id', $forum_id) . "
2231              AND poll_start = 0
2232              $sql_and";
2233      $result = $db->sql_query($sql);
2234  
2235      $topic_list = array();
2236      while ($row = $db->sql_fetchrow($result))
2237      {
2238          $topic_list[] = $row['topic_id'];
2239      }
2240      $db->sql_freeresult($result);
2241  
2242      if ($prune_flags & FORUM_FLAG_PRUNE_POLL)
2243      {
2244          $sql = 'SELECT topic_id
2245              FROM ' . TOPICS_TABLE . '
2246              WHERE ' . $db->sql_in_set('forum_id', $forum_id) . "
2247                  AND poll_start > 0
2248                  AND poll_last_vote < $prune_date
2249                  $sql_and";
2250          $result = $db->sql_query($sql);
2251  
2252          while ($row = $db->sql_fetchrow($result))
2253          {
2254              $topic_list[] = $row['topic_id'];
2255          }
2256          $db->sql_freeresult($result);
2257  
2258          $topic_list = array_unique($topic_list);
2259      }
2260  
2261      return delete_topics('topic_id', $topic_list, $auto_sync, false);
2262  }
2263  
2264  /**
2265  * Function auto_prune(), this function now relies on passed vars
2266  */
2267  function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_freq)
2268  {
2269      global $db;
2270  
2271      $sql = 'SELECT forum_name
2272          FROM ' . FORUMS_TABLE . "
2273          WHERE forum_id = $forum_id";
2274      $result = $db->sql_query($sql, 3600);
2275      $row = $db->sql_fetchrow($result);
2276      $db->sql_freeresult($result);
2277  
2278      if ($row)
2279      {
2280          $prune_date = time() - ($prune_days * 86400);
2281          $next_prune = time() + ($prune_freq * 86400);
2282  
2283          prune($forum_id, $prune_mode, $prune_date, $prune_flags, true);
2284  
2285          $sql = 'UPDATE ' . FORUMS_TABLE . "
2286              SET prune_next = $next_prune
2287              WHERE forum_id = $forum_id";
2288          $db->sql_query($sql);
2289  
2290          add_log('admin', 'LOG_AUTO_PRUNE', $row['forum_name']);
2291      }
2292  
2293      return;
2294  }
2295  
2296  /**
2297  * remove_comments will strip the sql comment lines out of an uploaded sql file
2298  * specifically for mssql and postgres type files in the install....
2299  *
2300  * @deprecated        Use phpbb_remove_comments() instead.
2301  */
2302  function remove_comments(&$output)
2303  {
2304      // Remove /* */ comments (http://ostermiller.org/findcomment.html)
2305      $output = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $output);
2306  
2307      // Return by reference and value.
2308      return $output;
2309  }
2310  
2311  /**
2312  * Cache moderators, called whenever permissions are changed via admin_permissions. Changes of username
2313  * and group names must be carried through for the moderators table
2314  */
2315  function cache_moderators()
2316  {
2317      global $db, $cache, $auth, $phpbb_root_path, $phpEx;
2318  
2319      // Remove cached sql results
2320      $cache->destroy('sql', MODERATOR_CACHE_TABLE);
2321  
2322      // Clear table
2323      switch ($db->sql_layer)
2324      {
2325          case 'sqlite':
2326          case 'firebird':
2327              $db->sql_query('DELETE FROM ' . MODERATOR_CACHE_TABLE);
2328          break;
2329  
2330          default:
2331              $db->sql_query('TRUNCATE TABLE ' . MODERATOR_CACHE_TABLE);
2332          break;
2333      }
2334  
2335      // We add moderators who have forum moderator permissions without an explicit ACL_NEVER setting
2336      $hold_ary = $ug_id_ary = $sql_ary = array();
2337  
2338      // Grab all users having moderative options...
2339      $hold_ary = $auth->acl_user_raw_data(false, 'm_%', false);
2340  
2341      // Add users?
2342      if (sizeof($hold_ary))
2343      {
2344          // At least one moderative option warrants a display
2345          $ug_id_ary = array_keys($hold_ary);
2346  
2347          // Remove users who have group memberships with DENY moderator permissions
2348          $sql = $db->sql_build_query('SELECT', array(
2349              'SELECT'    => 'a.forum_id, ug.user_id, g.group_id',
2350  
2351              'FROM'        => array(
2352                  ACL_OPTIONS_TABLE    => 'o',
2353                  USER_GROUP_TABLE    => 'ug',
2354                  GROUPS_TABLE        => 'g',
2355                  ACL_GROUPS_TABLE    => 'a',
2356              ),
2357  
2358              'LEFT_JOIN'    => array(
2359                  array(
2360                      'FROM'    => array(ACL_ROLES_DATA_TABLE => 'r'),
2361                      'ON'    => 'a.auth_role_id = r.role_id'
2362                  )
2363              ),
2364  
2365              'WHERE'        => '(o.auth_option_id = a.auth_option_id OR o.auth_option_id = r.auth_option_id)
2366                  AND ((a.auth_setting = ' . ACL_NEVER . ' AND r.auth_setting IS NULL)
2367                      OR r.auth_setting = ' . ACL_NEVER . ')
2368                  AND a.group_id = ug.group_id
2369                  AND g.group_id = ug.group_id
2370                  AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1)
2371                  AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . "
2372                  AND ug.user_pending = 0
2373                  AND o.auth_option " . $db->sql_like_expression('m_' . $db->any_char),
2374          ));
2375          $result = $db->sql_query($sql);
2376  
2377          while ($row = $db->sql_fetchrow($result))
2378          {
2379              if (isset($hold_ary[$row['user_id']][$row['forum_id']]))
2380              {
2381                  unset($hold_ary[$row['user_id']][$row['forum_id']]);
2382              }
2383          }
2384          $db->sql_freeresult($result);
2385  
2386          if (sizeof($hold_ary))
2387          {
2388              // Get usernames...
2389              $sql = 'SELECT user_id, username
2390                  FROM ' . USERS_TABLE . '
2391                  WHERE ' . $db->sql_in_set('user_id', array_keys($hold_ary));
2392              $result = $db->sql_query($sql);
2393  
2394              $usernames_ary = array();
2395              while ($row = $db->sql_fetchrow($result))
2396              {
2397                  $usernames_ary[$row['user_id']] = $row['username'];
2398              }
2399  
2400              foreach ($hold_ary as $user_id => $forum_id_ary)
2401              {
2402                  // Do not continue if user does not exist
2403                  if (!isset($usernames_ary[$user_id]))
2404                  {
2405                      continue;
2406                  }
2407  
2408                  foreach ($forum_id_ary as $forum_id => $auth_ary)
2409                  {
2410                      $sql_ary[] = array(
2411                          'forum_id'        => (int) $forum_id,
2412                          'user_id'        => (int) $user_id,
2413                          'username'        => (string) $usernames_ary[$user_id],
2414                          'group_id'        => 0,
2415                          'group_name'    => ''
2416                      );
2417                  }
2418              }
2419          }
2420      }
2421  
2422      // Now to the groups...
2423      $hold_ary = $auth->acl_group_raw_data(false, 'm_%', false);
2424  
2425      if (sizeof($hold_ary))
2426      {
2427          $ug_id_ary = array_keys($hold_ary);
2428  
2429          // Make sure not hidden or special groups are involved...
2430          $sql = 'SELECT group_name, group_id, group_type
2431              FROM ' . GROUPS_TABLE . '
2432              WHERE ' . $db->sql_in_set('group_id', $ug_id_ary);
2433          $result = $db->sql_query($sql);
2434  
2435          $groupnames_ary = array();
2436          while ($row = $db->sql_fetchrow($result))
2437          {
2438              if ($row['group_type'] == GROUP_HIDDEN || $row['group_type'] == GROUP_SPECIAL)
2439              {
2440                  unset($hold_ary[$row['group_id']]);
2441              }
2442  
2443              $groupnames_ary[$row['group_id']] = $row['group_name'];
2444          }
2445          $db->sql_freeresult($result);
2446  
2447          foreach ($hold_ary as $group_id => $forum_id_ary)
2448          {
2449              // If there is no group, we do not assign it...
2450              if (!isset($groupnames_ary[$group_id]))
2451              {
2452                  continue;
2453              }
2454  
2455              foreach ($forum_id_ary as $forum_id => $auth_ary)
2456              {
2457                  $flag = false;
2458                  foreach ($auth_ary as $auth_option => $setting)
2459                  {
2460                      // Make sure at least one ACL_YES option is set...
2461                      if ($setting == ACL_YES)
2462                      {
2463                          $flag = true;
2464                          break;
2465                      }
2466                  }
2467  
2468                  if (!$flag)
2469                  {
2470                      continue;
2471                  }
2472  
2473                  $sql_ary[] = array(
2474                      'forum_id'        => (int) $forum_id,
2475                      'user_id'        => 0,
2476                      'username'        => '',
2477                      'group_id'        => (int) $group_id,
2478                      'group_name'    => (string) $groupnames_ary[$group_id]
2479                  );
2480              }
2481          }
2482      }
2483  
2484      $db->sql_multi_insert(MODERATOR_CACHE_TABLE, $sql_ary);
2485  }
2486  
2487  /**
2488  * View log
2489  * If $log_count is set to false, we will skip counting all entries in the database.
2490  */
2491  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', $keywords = '')
2492  {
2493      global $db, $user, $auth, $phpEx, $phpbb_root_path, $phpbb_admin_path;
2494  
2495      $topic_id_list = $reportee_id_list = $is_auth = $is_mod = array();
2496  
2497      $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');
2498  
2499      switch ($mode)
2500      {
2501          case 'admin':
2502              $log_type = LOG_ADMIN;
2503              $sql_forum = '';
2504          break;
2505  
2506          case 'mod':
2507              $log_type = LOG_MOD;
2508              $sql_forum = '';
2509  
2510              if ($topic_id)
2511              {
2512                  $sql_forum = 'AND l.topic_id = ' . (int) $topic_id;
2513              }
2514              else if (is_array($forum_id))
2515              {
2516                  $sql_forum = 'AND ' . $db->sql_in_set('l.forum_id', array_map('intval', $forum_id));
2517              }
2518              else if ($forum_id)
2519              {
2520                  $sql_forum = 'AND l.forum_id = ' . (int) $forum_id;
2521              }
2522          break;
2523  
2524          case 'user':
2525              $log_type = LOG_USERS;
2526              $sql_forum = 'AND l.reportee_id = ' . (int) $user_id;
2527          break;
2528  
2529          case 'users':
2530              $log_type = LOG_USERS;
2531              $sql_forum = '';
2532          break;
2533  
2534          case 'critical':
2535              $log_type = LOG_CRITICAL;
2536              $sql_forum = '';
2537          break;
2538  
2539          default:
2540              return;
2541      }
2542  
2543      // Use no preg_quote for $keywords because this would lead to sole backslashes being added
2544      // We also use an OR connection here for spaces and the | string. Currently, regex is not supported for searching (but may come later).
2545      $keywords = preg_split('#[\s|]+#u', utf8_strtolower($keywords), 0, PREG_SPLIT_NO_EMPTY);
2546      $sql_keywords = '';
2547  
2548      if (!empty($keywords))
2549      {
2550          $keywords_pattern = array();
2551  
2552          // Build pattern and keywords...
2553          for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++)
2554          {
2555              $keywords_pattern[] = preg_quote($keywords[$i], '#');
2556              $keywords[$i] = $db->sql_like_expression($db->any_char . $keywords[$i] . $db->any_char);
2557          }
2558  
2559          $keywords_pattern = '#' . implode('|', $keywords_pattern) . '#ui';
2560  
2561          $operations = array();
2562          foreach ($user->lang as $key => $value)
2563          {
2564              if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value))
2565              {
2566                  $operations[] = $key;
2567              }
2568          }
2569  
2570          $sql_keywords = 'AND (';
2571          if (!empty($operations))
2572          {
2573              $sql_keywords .= $db->sql_in_set('l.log_operation', $operations) . ' OR ';
2574          }
2575          $sql_lower = $db->sql_lower_text('l.log_data');
2576          $sql_keywords .= "$sql_lower " . implode(" OR $sql_lower ", $keywords) . ')';
2577      }
2578  
2579      if ($log_count !== false)
2580      {
2581          $sql = 'SELECT COUNT(l.log_id) AS total_entries
2582              FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u
2583              WHERE l.log_type = $log_type
2584                  AND l.user_id = u.user_id
2585                  AND l.log_time >= $limit_days
2586                  $sql_keywords
2587                  $sql_forum";
2588          $result = $db->sql_query($sql);
2589          $log_count = (int) $db->sql_fetchfield('total_entries');
2590          $db->sql_freeresult($result);
2591      }
2592  
2593      // $log_count may be false here if false was passed in for it,
2594      // because in this case we did not run the COUNT() query above.
2595      // If we ran the COUNT() query and it returned zero rows, return;
2596      // otherwise query for logs below.
2597      if ($log_count === 0)
2598      {
2599          // Save the queries, because there are no logs to display
2600          return 0;
2601      }
2602  
2603      if ($offset >= $log_count)
2604      {
2605          $offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
2606      }
2607  
2608      $sql = "SELECT l.*, u.username, u.username_clean, u.user_colour
2609          FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u
2610          WHERE l.log_type = $log_type
2611              AND u.user_id = l.user_id
2612              " . (($limit_days) ? "AND l.log_time >= $limit_days" : '') . "
2613              $sql_keywords
2614              $sql_forum
2615          ORDER BY $sort_by";
2616      $result = $db->sql_query_limit($sql, $limit, $offset);
2617  
2618      $i = 0;
2619      $log = array();
2620      while ($row = $db->sql_fetchrow($result))
2621      {
2622          if ($row['topic_id'])
2623          {
2624              $topic_id_list[] = $row['topic_id'];
2625          }
2626  
2627          if ($row['reportee_id'])
2628          {
2629              $reportee_id_list[] = $row['reportee_id'];
2630          }
2631  
2632          $log[$i] = array(
2633              'id'                => $row['log_id'],
2634  
2635              'reportee_id'            => $row['reportee_id'],
2636              'reportee_username'        => '',
2637              'reportee_username_full'=> '',
2638  
2639              'user_id'            => $row['user_id'],
2640              'username'            => $row['username'],
2641              'username_full'        => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
2642  
2643              'ip'                => $row['log_ip'],
2644              'time'                => $row['log_time'],
2645              'forum_id'            => $row['forum_id'],
2646              'topic_id'            => $row['topic_id'],
2647  
2648              'viewforum'            => ($row['forum_id'] && $auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : false,
2649              'action'            => (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
2650          );
2651  
2652          if (!empty($row['log_data']))
2653          {
2654              $log_data_ary = @unserialize($row['log_data']);
2655              $log_data_ary = ($log_data_ary === false) ? array() : $log_data_ary;
2656  
2657              if (isset($user->lang[$row['log_operation']]))
2658              {
2659                  // Check if there are more occurrences of % than arguments, if there are we fill out the arguments array
2660                  // It doesn't matter if we add more arguments than placeholders
2661                  if ((substr_count($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0)
2662                  {
2663                      $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), ''));
2664                  }
2665  
2666                  $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary);
2667  
2668                  // If within the admin panel we do not censor text out
2669                  if (defined('IN_ADMIN'))
2670                  {
2671                      $log[$i]['action'] = bbcode_nl2br($log[$i]['action']);
2672                  }
2673                  else
2674                  {
2675                      $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action']));
2676                  }
2677              }
2678              else if (!empty($log_data_ary))
2679              {
2680                  $log[$i]['action'] .= '<br />' . implode('', $log_data_ary);
2681              }
2682  
2683              /* Apply make_clickable... has to be seen if it is for good. :/
2684              // Seems to be not for the moment, reconsider later...
2685              $log[$i]['action'] = make_clickable($log[$i]['action']);
2686              */
2687          }
2688  
2689          $i++;
2690      }
2691      $db->sql_freeresult($result);
2692  
2693      if (sizeof($topic_id_list))
2694      {
2695          $topic_id_list = array_unique($topic_id_list);
2696  
2697          // This query is not really needed if move_topics() updates the forum_id field,
2698          // although it's also used to determine if the topic still exists in the database
2699          $sql = 'SELECT topic_id, forum_id
2700              FROM ' . TOPICS_TABLE . '
2701              WHERE ' . $db->sql_in_set('topic_id', array_map('intval', $topic_id_list));
2702          $result = $db->sql_query($sql);
2703  
2704          $default_forum_id = 0;
2705  
2706          while ($row = $db->sql_fetchrow($result))
2707          {
2708              if (!$row['forum_id'])
2709              {
2710                  if ($auth->acl_getf_global('f_read'))
2711                  {
2712                      if (!$default_forum_id)
2713                      {
2714                          $sql = 'SELECT forum_id
2715                              FROM ' . FORUMS_TABLE . '
2716                              WHERE forum_type = ' . FORUM_POST;
2717                          $f_result = $db->sql_query_limit($sql, 1);
2718                          $default_forum_id = (int) $db->sql_fetchfield('forum_id', false, $f_result);
2719                          $db->sql_freeresult($f_result);
2720                      }
2721  
2722                      $is_auth[$row['topic_id']] = $default_forum_id;
2723                  }
2724              }
2725              else
2726              {
2727                  if ($auth->acl_get('f_read', $row['forum_id']))
2728                  {
2729                      $is_auth[$row['topic_id']] = $row['forum_id'];
2730                  }
2731              }
2732  
2733              if ($auth->acl_gets('a_', 'm_', $row['forum_id']))
2734              {
2735                  $is_mod[$row['topic_id']] = $row['forum_id'];
2736              }
2737          }
2738          $db->sql_freeresult($result);
2739  
2740          foreach ($log as $key => $row)
2741          {
2742              $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;
2743              $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;
2744          }
2745      }
2746  
2747      if (sizeof($reportee_id_list))
2748      {
2749          $reportee_id_list = array_unique($reportee_id_list);
2750          $reportee_names_list = array();
2751  
2752          $sql = 'SELECT user_id, username, user_colour
2753              FROM ' . USERS_TABLE . '
2754              WHERE ' . $db->sql_in_set('user_id', $reportee_id_list);
2755          $result = $db->sql_query($sql);
2756  
2757          while ($row = $db->sql_fetchrow($result))
2758          {
2759              $reportee_names_list[$row['user_id']] = $row;
2760          }
2761          $db->sql_freeresult($result);
2762  
2763          foreach ($log as $key => $row)
2764          {
2765              if (!isset($reportee_names_list[$row['reportee_id']]))
2766              {
2767                  continue;
2768              }
2769  
2770              $log[$key]['reportee_username'] = $reportee_names_list[$row['reportee_id']]['username'];
2771              $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);
2772          }
2773      }
2774  
2775      return $offset;
2776  }
2777  
2778  /**
2779  * Update foes - remove moderators and administrators from foe lists...
2780  */
2781  function update_foes($group_id = false, $user_id = false)
2782  {
2783      global $db, $auth;
2784  
2785      // update foes for some user
2786      if (is_array($user_id) && sizeof($user_id))
2787      {
2788          $sql = 'DELETE FROM ' . ZEBRA_TABLE . '
2789              WHERE ' . $db->sql_in_set('zebra_id', $user_id) . '
2790                  AND foe = 1';
2791          $db->sql_query($sql);
2792          return;
2793      }
2794  
2795      // update foes for some group
2796      if (is_array($group_id) && sizeof($group_id))
2797      {
2798          // Grab group settings...
2799          $sql = $db->sql_build_query('SELECT', array(
2800              'SELECT'    => 'a.group_id',
2801  
2802              'FROM'        => array(
2803                  ACL_OPTIONS_TABLE    => 'ao',
2804                  ACL_GROUPS_TABLE    => 'a'
2805              ),
2806  
2807              'LEFT_JOIN'    => array(
2808                  array(
2809                      'FROM'    => array(ACL_ROLES_DATA_TABLE => 'r'),
2810                      'ON'    => 'a.auth_role_id = r.role_id'
2811                  ),
2812              ),
2813  
2814              'WHERE'        => '(ao.auth_option_id = a.auth_option_id OR ao.auth_option_id = r.auth_option_id)
2815                  AND ' . $db->sql_in_set('a.group_id', $group_id) . "
2816                  AND ao.auth_option IN ('a_', 'm_')",
2817  
2818              'GROUP_BY'    => 'a.group_id'
2819          ));
2820          $result = $db->sql_query($sql);
2821  
2822          $groups = array();
2823          while ($row = $db->sql_fetchrow($result))
2824          {
2825              $groups[] = (int) $row['group_id'];
2826          }
2827          $db->sql_freeresult($result);
2828  
2829          if (!sizeof($groups))
2830          {
2831              return;
2832          }
2833  
2834          switch ($db->sql_layer)
2835          {
2836              case 'mysqli':
2837              case 'mysql4':
2838                  $sql = 'DELETE ' . (($db->sql_layer === 'mysqli' || version_compare($db->sql_server_info(true), '4.1', '>=')) ? 'z.*' : ZEBRA_TABLE) . '
2839                      FROM ' . ZEBRA_TABLE . ' z, ' . USER_GROUP_TABLE . ' ug
2840                      WHERE z.zebra_id = ug.user_id
2841                          AND z.foe = 1
2842                          AND ' . $db->sql_in_set('ug.group_id', $groups);
2843                  $db->sql_query($sql);
2844              break;
2845  
2846              default:
2847                  $sql = 'SELECT user_id
2848                      FROM ' . USER_GROUP_TABLE . '
2849                      WHERE ' . $db->sql_in_set('group_id', $groups);
2850                  $result = $db->sql_query($sql);
2851  
2852                  $users = array();
2853                  while ($row = $db->sql_fetchrow($result))
2854                  {
2855                      $users[] = (int) $row['user_id'];
2856                  }
2857                  $db->sql_freeresult($result);
2858  
2859                  if (sizeof($users))
2860                  {
2861                      $sql = 'DELETE FROM ' . ZEBRA_TABLE . '
2862                          WHERE ' . $db->sql_in_set('zebra_id', $users) . '
2863                              AND foe = 1';
2864                      $db->sql_query($sql);
2865                  }
2866              break;
2867          }
2868  
2869          return;
2870      }
2871  
2872      // update foes for everyone
2873      $perms = array();
2874      foreach ($auth->acl_get_list(false, array('a_', 'm_'), false) as $forum_id => $forum_ary)
2875      {
2876          foreach ($forum_ary as $auth_option => $user_ary)
2877          {
2878              $perms = array_merge($perms, $user_ary);
2879          }
2880      }
2881  
2882      if (sizeof($perms))
2883      {
2884          $sql = 'DELETE FROM ' . ZEBRA_TABLE . '
2885              WHERE ' . $db->sql_in_set('zebra_id', array_unique($perms)) . '
2886                  AND foe = 1';
2887          $db->sql_query($sql);
2888      }
2889      unset($perms);
2890  }
2891  
2892  /**
2893  * Lists inactive users
2894  */
2895  function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_inactive_time DESC')
2896  {
2897      global $db, $user;
2898  
2899      $sql = 'SELECT COUNT(user_id) AS user_count
2900          FROM ' . USERS_TABLE . '
2901          WHERE user_type = ' . USER_INACTIVE .
2902          (($limit_days) ? " AND user_inactive_time >= $limit_days" : '');
2903      $result = $db->sql_query($sql);
2904      $user_count = (int) $db->sql_fetchfield('user_count');
2905      $db->sql_freeresult($result);
2906  
2907      if ($user_count == 0)
2908      {
2909          // Save the queries, because there are no users to display
2910          return 0;
2911      }
2912  
2913      if ($offset >= $user_count)
2914      {
2915          $offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
2916      }
2917  
2918      $sql = 'SELECT *
2919          FROM ' . USERS_TABLE . '
2920          WHERE user_type = ' . USER_INACTIVE .
2921          (($limit_days) ? " AND user_inactive_time >= $limit_days" : '') . "
2922          ORDER BY $sort_by";
2923      $result = $db->sql_query_limit($sql, $limit, $offset);
2924  
2925      while ($row = $db->sql_fetchrow($result))
2926      {
2927          $row['inactive_reason'] = $user->lang['INACTIVE_REASON_UNKNOWN'];
2928          switch ($row['user_inactive_reason'])
2929          {
2930              case INACTIVE_REGISTER:
2931                  $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REGISTER'];
2932              break;
2933  
2934              case INACTIVE_PROFILE:
2935                  $row['inactive_reason'] = $user->lang['INACTIVE_REASON_PROFILE'];
2936              break;
2937  
2938              case INACTIVE_MANUAL:
2939                  $row['inactive_reason'] = $user->lang['INACTIVE_REASON_MANUAL'];
2940              break;
2941  
2942              case INACTIVE_REMIND:
2943                  $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REMIND'];
2944              break;
2945          }
2946  
2947          $users[] = $row;
2948      }
2949  
2950      return $offset;
2951  }
2952  
2953  /**
2954  * Lists warned users
2955  */
2956  function view_warned_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_warnings DESC')
2957  {
2958      global $db;
2959  
2960      $sql = 'SELECT user_id, username, user_colour, user_warnings, user_last_warning
2961          FROM ' . USERS_TABLE . '
2962          WHERE user_warnings > 0
2963          ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '') . "
2964          ORDER BY $sort_by";
2965      $result = $db->sql_query_limit($sql, $limit, $offset);
2966      $users = $db->sql_fetchrowset($result);
2967      $db->sql_freeresult($result);
2968  
2969      $sql = 'SELECT count(user_id) AS user_count
2970          FROM ' . USERS_TABLE . '
2971          WHERE user_warnings > 0
2972          ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '');
2973      $result = $db->sql_query($sql);
2974      $user_count = (int) $db->sql_fetchfield('user_count');
2975      $db->sql_freeresult($result);
2976  
2977      return;
2978  }
2979  
2980  /**
2981  * Get database size
2982  * Currently only mysql and mssql are supported
2983  */
2984  function get_database_size()
2985  {
2986      global $db, $user, $table_prefix;
2987  
2988      $database_size = false;
2989  
2990      // This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0
2991      switch ($db->sql_layer)
2992      {
2993          case 'mysql':
2994          case 'mysql4':
2995          case 'mysqli':
2996              $sql = 'SELECT VERSION() AS mysql_version';
2997              $result = $db->sql_query($sql);
2998              $row = $db->sql_fetchrow($result);
2999              $db->sql_freeresult($result);
3000  
3001              if ($row)
3002              {
3003                  $version = $row['mysql_version'];
3004  
3005                  if (preg_match('#(3\.23|[45]\.)#', $version))
3006                  {
3007                      $db_name = (preg_match('#^(?:3\.23\.(?:[6-9]|[1-9]{2}))|[45]\.#', $version)) ? "`{$db->dbname}`" : $db->dbname;
3008  
3009                      $sql = 'SHOW TABLE STATUS
3010                          FROM ' . $db_name;
3011                      $result = $db->sql_query($sql, 7200);
3012  
3013                      $database_size = 0;
3014                      while ($row = $db->sql_fetchrow($result))
3015                      {
3016                          if ((isset($row['Type']) && $row['Type'] != 'MRG_MyISAM') || (isset($row['Engine']) && ($row['Engine'] == 'MyISAM' || $row['Engine'] == 'InnoDB')))
3017                          {
3018                              if ($table_prefix != '')
3019                              {
3020                                  if (strpos($row['Name'], $table_prefix) !== false)
3021                                  {
3022                                      $database_size += $row['Data_length'] + $row['Index_length'];
3023                                  }
3024                              }
3025                              else
3026                              {
3027                                  $database_size += $row['Data_length'] + $row['Index_length'];
3028                              }
3029                          }
3030                      }
3031                      $db->sql_freeresult($result);
3032                  }
3033              }
3034          break;
3035  
3036          case 'firebird':
3037              global $dbname;
3038  
3039              // if it on the local machine, we can get lucky
3040              if (file_exists($dbname))
3041              {
3042                  $database_size = filesize($dbname);
3043              }
3044  
3045          break;
3046  
3047          case 'sqlite':
3048              global $dbhost;
3049  
3050              if (file_exists($dbhost))
3051              {
3052                  $database_size = filesize($dbhost);
3053              }
3054  
3055          break;
3056  
3057          case 'mssql':
3058          case 'mssql_odbc':
3059          case 'mssqlnative':
3060              $sql = 'SELECT ((SUM(size) * 8.0) * 1024.0) as dbsize
3061                  FROM sysfiles';
3062              $result = $db->sql_query($sql, 7200);
3063              $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false;
3064              $db->sql_freeresult($result);
3065          break;
3066  
3067          case 'postgres':
3068              $sql = "SELECT proname
3069                  FROM pg_proc
3070                  WHERE proname = 'pg_database_size'";
3071              $result = $db->sql_query($sql);
3072              $row = $db->sql_fetchrow($result);
3073              $db->sql_freeresult($result);
3074  
3075              if ($row['proname'] == 'pg_database_size')
3076              {
3077                  $database = $db->dbname;
3078                  if (strpos($database, '.') !== false)
3079                  {
3080                      list($database, ) = explode('.', $database);
3081                  }
3082  
3083                  $sql = "SELECT oid
3084                      FROM pg_database
3085                      WHERE datname = '$database'";
3086                  $result = $db->sql_query($sql);
3087                  $row = $db->sql_fetchrow($result);
3088                  $db->sql_freeresult($result);
3089  
3090                  $oid = $row['oid'];
3091  
3092                  $sql = 'SELECT pg_database_size(' . $oid . ') as size';
3093                  $result = $db->sql_query($sql);
3094                  $row = $db->sql_fetchrow($result);
3095                  $db->sql_freeresult($result);
3096  
3097                  $database_size = $row['size'];
3098              }
3099          break;
3100  
3101          case 'oracle':
3102              $sql = 'SELECT SUM(bytes) as dbsize
3103                  FROM user_segments';
3104              $result = $db->sql_query($sql, 7200);
3105              $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false;
3106              $db->sql_freeresult($result);
3107          break;
3108      }
3109  
3110      $database_size = ($database_size !== false) ? get_formatted_filesize($database_size) : $user->lang['NOT_AVAILABLE'];
3111  
3112      return $database_size;
3113  }
3114  
3115  /**
3116  * Retrieve contents from remotely stored file
3117  */
3118  function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port = 80, $timeout = 6)
3119  {
3120      global $user;
3121  
3122      if ($fsock = @fsockopen($host, $port, $errno, $errstr, $timeout))
3123      {
3124          @fputs($fsock, "GET $directory/$filename HTTP/1.0\r\n");
3125          @fputs($fsock, "HOST: $host\r\n");
3126          @fputs($fsock, "Connection: close\r\n\r\n");
3127  
3128          $timer_stop = time() + $timeout;
3129          stream_set_timeout($fsock, $timeout);
3130  
3131          $file_info = '';
3132          $get_info = false;
3133  
3134          while (!@feof($fsock))
3135          {
3136              if ($get_info)
3137              {
3138                  $file_info .= @fread($fsock, 1024);
3139              }
3140              else
3141              {
3142                  $line = @fgets($fsock, 1024);
3143                  if ($line == "\r\n")
3144                  {
3145                      $get_info = true;
3146                  }
3147                  else if (stripos($line, '404 not found') !== false)
3148                  {
3149                      $errstr = $user->lang['FILE_NOT_FOUND'] . ': ' . $filename;
3150                      return false;
3151                  }
3152              }
3153  
3154              $stream_meta_data = stream_get_meta_data($fsock);
3155  
3156              if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop)
3157              {
3158                  $errstr = $user->lang['FSOCK_TIMEOUT'];
3159                  return false;
3160              }
3161          }
3162          @fclose($fsock);
3163      }
3164      else
3165      {
3166          if ($errstr)
3167          {
3168              $errstr = utf8_convert_message($errstr);
3169              return false;
3170          }
3171          else
3172          {
3173              $errstr = $user->lang['FSOCK_DISABLED'];
3174              return false;
3175          }
3176      }
3177  
3178      return $file_info;
3179  }
3180  
3181  /**
3182  * Tidy Warnings
3183  * Remove all warnings which have now expired from the database
3184  * The duration of a warning can be defined by the administrator
3185  * This only removes the warning and reduces the associated count,
3186  * it does not remove the user note recording the contents of the warning
3187  */
3188  function tidy_warnings()
3189  {
3190      global $db, $config;
3191  
3192      $expire_date = time() - ($config['warnings_expire_days'] * 86400);
3193      $warning_list = $user_list = array();
3194  
3195      $sql = 'SELECT * FROM ' . WARNINGS_TABLE . "
3196          WHERE warning_time < $expire_date";
3197      $result = $db->sql_query($sql);
3198  
3199      while ($row = $db->sql_fetchrow($result))
3200      {
3201          $warning_list[] = $row['warning_id'];
3202          $user_list[$row['user_id']] = isset($user_list[$row['user_id']]) ? ++$user_list[$row['user_id']] : 1;
3203      }
3204      $db->sql_freeresult($result);
3205  
3206      if (sizeof($warning_list))
3207      {
3208          $db->sql_transaction('begin');
3209  
3210          $sql = 'DELETE FROM ' . WARNINGS_TABLE . '
3211              WHERE ' . $db->sql_in_set('warning_id', $warning_list);
3212          $db->sql_query($sql);
3213  
3214          foreach ($user_list as $user_id => $value)
3215          {
3216              $sql = 'UPDATE ' . USERS_TABLE . " SET user_warnings = user_warnings - $value
3217                  WHERE user_id = $user_id";
3218              $db->sql_query($sql);
3219          }
3220  
3221          $db->sql_transaction('commit');
3222      }
3223  
3224      set_config('warnings_last_gc', time(), true);
3225  }
3226  
3227  /**
3228  * Tidy database, doing some maintanance tasks
3229  */
3230  function tidy_database()
3231  {
3232      global $db;
3233  
3234      // Here we check permission consistency
3235  
3236      // Sometimes, it can happen permission tables having forums listed which do not exist
3237      $sql = 'SELECT forum_id
3238          FROM ' . FORUMS_TABLE;
3239      $result = $db->sql_query($sql);
3240  
3241      $forum_ids = array(0);
3242      while ($row = $db->sql_fetchrow($result))
3243      {
3244          $forum_ids[] = $row['forum_id'];
3245      }
3246      $db->sql_freeresult($result);
3247  
3248      // Delete those rows from the acl tables not having listed the forums above
3249      $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . '
3250          WHERE ' . $db->sql_in_set('forum_id', $forum_ids, true);
3251      $db->sql_query($sql);
3252  
3253      $sql = 'DELETE FROM ' . ACL_USERS_TABLE . '
3254          WHERE ' . $db->sql_in_set('forum_id', $forum_ids, true);
3255      $db->sql_query($sql);
3256  
3257      set_config('database_last_gc', time(), true);
3258  }
3259  
3260  /**
3261  * Add permission language - this will make sure custom files will be included
3262  */
3263  function add_permission_language()
3264  {
3265      global $user, $phpEx;
3266  
3267      // First of all, our own file. We need to include it as the first file because it presets all relevant variables.
3268      $user->add_lang('acp/permissions_phpbb');
3269  
3270      $files_to_add = array();
3271  
3272      // Now search in acp and mods folder for permissions_ files.
3273      foreach (array('acp/', 'mods/') as $path)
3274      {
3275          $dh = @opendir($user->lang_path . $user->lang_name . '/' . $path);
3276  
3277          if ($dh)
3278          {
3279              while (($file = readdir($dh)) !== false)
3280              {
3281                  if ($file !== 'permissions_phpbb.' . $phpEx && strpos($file, 'permissions_') === 0 && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx)
3282                  {
3283                      $files_to_add[] = $path . substr($file, 0, -(strlen($phpEx) + 1));
3284                  }
3285              }
3286              closedir($dh);
3287          }
3288      }
3289  
3290      if (!sizeof($files_to_add))
3291      {
3292          return false;
3293      }
3294  
3295      $user->add_lang($files_to_add);
3296      return true;
3297  }
3298  
3299  /**
3300   * Obtains the latest version information
3301   *
3302   * @param bool $force_update Ignores cached data. Defaults to false.
3303   * @param bool $warn_fail Trigger a warning if obtaining the latest version information fails. Defaults to false.
3304   * @param int $ttl Cache version information for $ttl seconds. Defaults to 86400 (24 hours).
3305   *
3306   * @return string | false Version info on success, false on failure.
3307   */
3308  function obtain_latest_version_info($force_update = false, $warn_fail = false, $ttl = 86400)
3309  {
3310      global $cache;
3311  
3312      $info = $cache->get('versioncheck');
3313  
3314      if ($info === false || $force_update)
3315      {
3316          $errstr = '';
3317          $errno = 0;
3318  
3319          $info = get_remote_file('version.phpbb.com', '/phpbb',
3320                  ((defined('PHPBB_QA')) ? '30x_qa.txt' : '30x.txt'), $errstr, $errno);
3321  
3322          if (empty($info))
3323          {
3324              $cache->destroy('versioncheck');
3325              if ($warn_fail)
3326              {
3327                  trigger_error($errstr, E_USER_WARNING);
3328              }
3329              return false;
3330          }
3331  
3332          $cache->put('versioncheck', $info, $ttl);
3333      }
3334  
3335      return $info;
3336  }
3337  
3338  /**
3339   * Enables a particular flag in a bitfield column of a given table.
3340   *
3341   * @param string    $table_name        The table to update
3342   * @param string    $column_name    The column containing a bitfield to update
3343   * @param int        $flag            The binary flag which is OR-ed with the current column value
3344   * @param string    $sql_more        This string is attached to the sql query generated to update the table.
3345   *
3346   * @return null
3347   */
3348  function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more = '')
3349  {
3350      global $db;
3351  
3352      $sql = 'UPDATE ' . $table_name . '
3353          SET ' . $column_name . ' = ' . $db->sql_bit_or($column_name, $flag) . '
3354          ' . $sql_more;
3355      $db->sql_query($sql);
3356  }
3357  
3358  ?>


Generated: Wed Oct 2 15:03:47 2013 Cross-referenced by PHPXref 0.7.1