[ Index ]

PHP Cross Reference of MyBB 1.8.27

title

Body

[close]

/inc/ -> class_moderation.php (source)

   1  <?php
   2  /**
   3   * MyBB 1.8
   4   * Copyright 2014 MyBB Group, All Rights Reserved
   5   *
   6   * Website: http://www.mybb.com
   7   * License: http://www.mybb.com/about/license
   8   *
   9   */
  10  
  11  class Moderation
  12  {
  13      /**
  14       * Close one or more threads
  15       *
  16       * @param array|int $tids Thread ID(s)
  17       * @return boolean true
  18       */
  19  	function close_threads($tids)
  20      {
  21          global $db, $plugins;
  22  
  23          if(!is_array($tids))
  24          {
  25              $tids = array($tids);
  26          }
  27  
  28          // Make sure we only have valid values
  29          $tids = array_map('intval', $tids);
  30  
  31          $plugins->run_hooks("class_moderation_close_threads", $tids);
  32  
  33          $tid_list = implode(',', $tids);
  34  
  35          $openthread = array(
  36              "closed" => 1,
  37          );
  38          $db->update_query("threads", $openthread, "tid IN ($tid_list) AND closed NOT LIKE 'moved|%'");
  39  
  40          return true;
  41      }
  42  
  43      /**
  44       * Open one or more threads
  45       *
  46       * @param array|int $tids Thread ID(s)
  47       * @return boolean
  48       */
  49  
  50  	function open_threads($tids)
  51      {
  52          global $db, $plugins;
  53  
  54          if(!is_array($tids))
  55          {
  56              $tids = array($tids);
  57          }
  58  
  59          if(empty($tids))
  60          {
  61              return false;
  62          }
  63  
  64          // Make sure we only have valid values
  65          $tids = array_map('intval', $tids);
  66  
  67          $plugins->run_hooks("class_moderation_open_threads", $tids);
  68  
  69          $tid_list = implode(',', $tids);
  70  
  71          $closethread = array(
  72              "closed" => 0,
  73          );
  74          $db->update_query("threads", $closethread, "tid IN ($tid_list)");
  75  
  76          return true;
  77      }
  78  
  79      /**
  80       * Stick one or more threads
  81       *
  82       * @param array|int $tids Thread ID(s)
  83       * @return boolean
  84       */
  85  	function stick_threads($tids)
  86      {
  87          global $db, $plugins;
  88  
  89          if(!is_array($tids))
  90          {
  91              $tids = array($tids);
  92          }
  93  
  94          if(empty($tids))
  95          {
  96              return false;
  97          }
  98  
  99          // Make sure we only have valid values
 100          $tids = array_map('intval', $tids);
 101  
 102          $plugins->run_hooks("class_moderation_stick_threads", $tids);
 103  
 104          $tid_list = implode(',', $tids);
 105  
 106          $stickthread = array(
 107              "sticky" => 1,
 108          );
 109          $db->update_query("threads", $stickthread, "tid IN ($tid_list)");
 110  
 111          return true;
 112      }
 113  
 114      /**
 115       * Unstick one or more thread
 116       *
 117       * @param array|int $tids Thread ID(s)
 118       * @return boolean
 119       */
 120  	function unstick_threads($tids)
 121      {
 122          global $db, $plugins;
 123  
 124          if(!is_array($tids))
 125          {
 126              $tids = array($tids);
 127          }
 128  
 129          if(empty($tids))
 130          {
 131              return false;
 132          }
 133  
 134          // Make sure we only have valid values
 135          $tids = array_map('intval', $tids);
 136  
 137          $plugins->run_hooks("class_moderation_unstick_threads", $tids);
 138  
 139          $tid_list = implode(',', $tids);
 140  
 141          $unstickthread = array(
 142              "sticky" => 0,
 143          );
 144          $db->update_query("threads", $unstickthread, "tid IN ($tid_list)");
 145  
 146          return true;
 147      }
 148  
 149      /**
 150       * Remove redirects that redirect to the specified thread
 151       *
 152       * @param int $tid Thread ID of the thread
 153       * @return boolean
 154       */
 155  	function remove_redirects($tid)
 156      {
 157          global $db, $plugins;
 158  
 159          $plugins->run_hooks("class_moderation_remove_redirects", $tid);
 160  
 161          // Delete the redirects
 162          $tid = (int)$tid;
 163          if(empty($tid))
 164          {
 165              return false;
 166          }
 167  
 168          $query = $db->simple_select('threads', 'tid', "closed='moved|$tid'");
 169          while($redirect_tid = $db->fetch_field($query, 'tid'))
 170          {
 171              $this->delete_thread($redirect_tid);
 172          }
 173  
 174          return true;
 175      }
 176  
 177      /**
 178       * Delete a thread
 179       *
 180       * @param int $tid Thread ID of the thread
 181       * @return boolean
 182       */
 183  	function delete_thread($tid)
 184      {
 185          global $db, $cache, $plugins;
 186  
 187          $tid = (int)$tid;
 188  
 189          $plugins->run_hooks("class_moderation_delete_thread_start", $tid);
 190  
 191          $thread = get_thread($tid);
 192          if(!$thread)
 193          {
 194              return false;
 195          }
 196          $forum = get_forum($thread['fid']);
 197  
 198          $userposts = array();
 199  
 200          // Find the pid, uid, visibility, and forum post count status
 201          $query = $db->simple_select('posts', 'pid, uid, visible', "tid='{$tid}'");
 202          $pids = array();
 203          $num_unapproved_posts = $num_approved_posts = $num_deleted_posts = 0;
 204          while($post = $db->fetch_array($query))
 205          {
 206              $pids[] = $post['pid'];
 207  
 208              if(!function_exists("remove_attachments"))
 209              {
 210                  require_once  MYBB_ROOT."inc/functions_upload.php";
 211              }
 212  
 213              // Remove attachments
 214              remove_attachments($post['pid']);
 215  
 216              // If the post is unapproved, count it!
 217              if(($post['visible'] == 0 && $thread['visible'] != -1) || $thread['visible'] == 0)
 218              {
 219                  $num_unapproved_posts++;
 220              }
 221              elseif($post['visible'] == -1 || $thread['visible'] == -1)
 222              {
 223                  $num_deleted_posts++;
 224              }
 225              else
 226              {
 227                  $num_approved_posts++;
 228  
 229                  // Count the post counts for each user to be subtracted
 230                  if($forum['usepostcounts'] != 0)
 231                  {
 232                      if(!isset($userposts[$post['uid']]['num_posts']))
 233                      {
 234                          $userposts[$post['uid']]['num_posts'] = 0;
 235                      }
 236                      ++$userposts[$post['uid']]['num_posts'];
 237                  }
 238              }
 239          }
 240  
 241          if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|')
 242          {
 243              if(!isset($userposts[$thread['uid']]['num_threads']))
 244              {
 245                  $userposts[$thread['uid']]['num_threads'] = 0;
 246              }
 247              ++$userposts[$thread['uid']]['num_threads'];
 248          }
 249  
 250          // Remove post count from users
 251          if($thread['visible'] == 1)
 252          {
 253              if(!empty($userposts))
 254              {
 255                  foreach($userposts as $uid => $subtract)
 256                  {
 257                      $update_array = array(
 258                          "postnum" => "-{$subtract['num_posts']}",
 259                          "threadnum" => "-{$subtract['num_threads']}",
 260                      );
 261                      update_user_counters($uid, $update_array);
 262                  }
 263              }
 264          }
 265          // Delete posts and their attachments
 266          if(!empty($pids))
 267          {
 268              $pids = implode(',', $pids);
 269              $db->delete_query("posts", "pid IN ($pids)");
 270              $db->delete_query("attachments", "pid IN ($pids)");
 271              $db->delete_query("reportedcontent", "id IN ($pids) AND (type = 'post' OR type = '')");
 272          }
 273  
 274          // Delete threads, redirects, subscriptions, polls, and poll votes
 275          $db->delete_query("threads", "tid='$tid'");
 276          $query = $db->simple_select('threads', 'tid', "closed='moved|$tid'");
 277          while($redirect_tid = $db->fetch_field($query, 'tid'))
 278          {
 279              $this->delete_thread($redirect_tid);
 280          }
 281          $db->delete_query("threadsubscriptions", "tid='$tid'");
 282          $db->delete_query("polls", "tid='$tid'");
 283          $db->delete_query("pollvotes", "pid='".$thread['poll']."'");
 284          $db->delete_query("threadsread", "tid='$tid'");
 285          $db->delete_query("threadratings", "tid='$tid'");
 286  
 287          $updated_counters = array(
 288              "posts" => "-{$num_approved_posts}",
 289              "unapprovedposts" => "-{$num_unapproved_posts}",
 290              "deletedposts" => "-{$num_deleted_posts}"
 291          );
 292  
 293          if($thread['visible'] == 1)
 294          {
 295              $updated_counters['threads'] = -1;
 296          }
 297          elseif($thread['visible'] == -1)
 298          {
 299              $updated_counters['deletedthreads'] = -1;
 300          }
 301          else
 302          {
 303              $updated_counters['unapprovedthreads'] = -1;
 304          }
 305  
 306          if(strpos($thread['closed'], 'moved|') !== false)
 307          {
 308              // Redirect
 309              if($thread['visible'] == 1)
 310              {
 311                  $updated_counters['posts'] = -1;
 312              }
 313              elseif($thread['visible'] == -1)
 314              {
 315                  $updated_counters['deletedposts'] = -1;
 316              }
 317              else
 318              {
 319                  $updated_counters['unapprovedposts'] = -1;
 320              }
 321          }
 322  
 323          // Update forum count
 324          update_forum_counters($thread['fid'], $updated_counters);
 325          update_forum_lastpost($thread['fid']);
 326          mark_reports($tid, 'thread');
 327  
 328          $plugins->run_hooks("class_moderation_delete_thread", $tid);
 329  
 330          return true;
 331      }
 332  
 333      /**
 334       * Delete a poll
 335       *
 336       * @param int $pid Poll id
 337       * @return boolean
 338       */
 339  	function delete_poll($pid)
 340      {
 341          global $db, $plugins;
 342  
 343          $pid = (int)$pid;
 344  
 345          if(empty($pid))
 346          {
 347              return false;
 348          }
 349  
 350          $plugins->run_hooks("class_moderation_delete_poll", $pid);
 351  
 352          $db->delete_query("polls", "pid='$pid'");
 353          $db->delete_query("pollvotes", "pid='$pid'");
 354          $pollarray = array(
 355              'poll' => '0',
 356          );
 357          $db->update_query("threads", $pollarray, "poll='$pid'");
 358  
 359          return true;
 360      }
 361  
 362      /**
 363       * Approve one or more threads
 364       *
 365       * @param array|int $tids Thread ID(s)
 366       * @return boolean
 367       */
 368  	function approve_threads($tids)
 369      {
 370          global $db, $cache, $plugins;
 371  
 372          if(!is_array($tids))
 373          {
 374              $tids = array($tids);
 375          }
 376  
 377          if(empty($tids))
 378          {
 379              return false;
 380          }
 381  
 382          // Make sure we only have valid values
 383          $tids = array_map('intval', $tids);
 384  
 385          $tid_list = $forum_counters = $user_counters = $posts_to_approve = array();
 386  
 387          $tids_list = implode(",", $tids);
 388          $query = $db->simple_select("threads", "*", "tid IN ($tids_list)");
 389  
 390          while($thread = $db->fetch_array($query))
 391          {
 392              if($thread['visible'] == 1 || $thread['visible'] == -1)
 393              {
 394                  continue;
 395              }
 396              $tid_list[] = $thread['tid'];
 397  
 398              $forum = get_forum($thread['fid']);
 399  
 400              if(!isset($forum_counters[$forum['fid']]))
 401              {
 402                  $forum_counters[$forum['fid']] = array(
 403                      'num_posts' => 0,
 404                      'num_threads' => 0,
 405                      'num_deleted_posts' => 0,
 406                      'num_unapproved_posts' => 0
 407                  );
 408              }
 409  
 410              if(!isset($user_counters[$thread['uid']]))
 411              {
 412                  $user_counters[$thread['uid']] = array(
 413                      'num_posts' => 0,
 414                      'num_threads' => 0
 415                  );
 416              }
 417  
 418              ++$forum_counters[$forum['fid']]['num_threads'];
 419              $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Remove implied visible from count
 420              $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['deletedposts'];
 421              $forum_counters[$forum['fid']]['num_unapproved_posts'] += $thread['deletedposts']+$thread['replies']+1;
 422  
 423              if($forum['usepostcounts'] != 0)
 424              {
 425                  // On approving thread restore user post counts
 426                  $query = $db->simple_select("posts", "COUNT(pid) as posts, uid", "tid='{$thread['tid']}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid");
 427                  while($counter = $db->fetch_array($query))
 428                  {
 429                      $user_counters[$counter['uid']]['num_posts'] += $counter['posts'];
 430                  }
 431              }
 432  
 433              if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|')
 434              {
 435                  ++$user_counters[$thread['uid']]['num_threads'];
 436              }
 437  
 438              $posts_to_approve[] = $thread['firstpost'];
 439          }
 440  
 441          if(!empty($tid_list))
 442          {
 443              $tid_moved_list = "";
 444              $comma = "";
 445              foreach($tid_list as $tid)
 446              {
 447                  $tid_moved_list .= "{$comma}'moved|{$tid}'";
 448                  $comma = ",";
 449              }
 450              $tid_list = implode(',', $tid_list);
 451              $approve = array(
 452                  "visible" => 1
 453              );
 454              $db->update_query("threads", $approve, "tid IN ($tid_list)");
 455              // Approve redirects, too
 456              $redirect_tids = array();
 457              $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})");
 458              while($redirect_tid = $db->fetch_field($query, 'tid'))
 459              {
 460                  $redirect_tids[] = $redirect_tid;
 461              }
 462              if(!empty($redirect_tids))
 463              {
 464                  $this->approve_threads($redirect_tids);
 465              }
 466              if(!empty($posts_to_approve))
 467              {
 468                  $db->update_query("posts", $approve, "pid IN (".implode(',', $posts_to_approve).")");
 469              }
 470  
 471              $plugins->run_hooks("class_moderation_approve_threads", $tids);
 472  
 473              if(!empty($forum_counters))
 474              {
 475                  foreach($forum_counters as $fid => $counters)
 476                  {
 477                      // Update stats
 478                      $update_array = array(
 479                          "threads" => "+{$counters['num_threads']}",
 480                          "unapprovedthreads" => "-{$counters['num_threads']}",
 481                          "posts" => "+{$counters['num_posts']}",
 482                          "unapprovedposts" => "-{$counters['num_unapproved_posts']}",
 483                          "deletedposts" => "+{$counters['num_deleted_posts']}"
 484                      );
 485                      update_forum_counters($fid, $update_array);
 486                      update_forum_lastpost($fid);
 487                  }
 488              }
 489  
 490              if(!empty($user_counters))
 491              {
 492                  foreach($user_counters as $uid => $counters)
 493                  {
 494                      $update_array = array(
 495                          "postnum" => "+{$counters['num_posts']}",
 496                          "threadnum" => "+{$counters['num_threads']}",
 497                      );
 498                      update_user_counters($uid, $update_array);
 499                  }
 500              }
 501          }
 502          return true;
 503      }
 504  
 505      /**
 506       * Unapprove one or more threads
 507       *
 508       * @param array|int $tids Thread ID(s)
 509       * @return boolean
 510       */
 511  	function unapprove_threads($tids)
 512      {
 513          global $db, $cache, $plugins;
 514  
 515          if(!is_array($tids))
 516          {
 517              $tids = array($tids);
 518          }
 519  
 520          if(empty($tids))
 521          {
 522              return false;
 523          }
 524  
 525          // Make sure we only have valid values
 526          $tids = array_map('intval', $tids);
 527  
 528          $tid_list = implode(',', $tids);
 529          $tid_moved_list = "";
 530          $comma = "";
 531          foreach($tids as $tid)
 532          {
 533              $tid_moved_list .= "{$comma}'moved|{$tid}'";
 534              $comma = ",";
 535          }
 536  
 537          $forum_counters = $user_counters = $posts_to_unapprove = array();
 538  
 539          $tids_list = implode(",", $tids);
 540          $query = $db->simple_select("threads", "*", "tid IN ($tids_list)");
 541  
 542          while($thread = $db->fetch_array($query))
 543          {
 544              $forum = get_forum($thread['fid']);
 545  
 546              if($thread['visible'] == 1 || $thread['visible'] == -1)
 547              {
 548                  if(!isset($forum_counters[$forum['fid']]))
 549                  {
 550                      $forum_counters[$forum['fid']] = array(
 551                          'num_threads' => 0,
 552                          'num_posts' => 0,
 553                          'num_unapprovedthreads' => 0,
 554                          'num_unapprovedposts' => 0,
 555                          'num_deletedthreads' => 0,
 556                          'num_deletedposts' => 0
 557                      );
 558                  }
 559  
 560                  if(!isset($user_counters[$thread['uid']]))
 561                  {
 562                      $user_counters[$thread['uid']] = array(
 563                          'num_posts' => 0,
 564                          'num_threads' => 0
 565                      );
 566                  }
 567  
 568                  ++$forum_counters[$forum['fid']]['num_unapprovedthreads'];
 569                  $forum_counters[$forum['fid']]['num_unapprovedposts'] += $thread['replies']+$thread['deletedposts']+1;
 570  
 571                  if($thread['visible'] == 1)
 572                  {
 573                      ++$forum_counters[$forum['fid']]['num_threads'];
 574                      $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Add implied invisible to count
 575                      $forum_counters[$forum['fid']]['num_deletedposts'] += $thread['deletedposts'];
 576                  }
 577                  else
 578                  {
 579                      ++$forum_counters[$forum['fid']]['num_deletedthreads'];
 580                      $forum_counters[$forum['fid']]['num_deletedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Add implied invisible to count
 581                      $forum_counters[$forum['fid']]['num_unapprovedposts'] += $thread['unapprovedposts'];
 582                  }
 583  
 584                  // On unapproving thread update user post counts
 585                  if($thread['visible'] == 1 && $forum['usepostcounts'] != 0)
 586                  {
 587                      $query = $db->simple_select("posts", "COUNT(pid) AS posts, uid", "tid='{$thread['tid']}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid");
 588                      while($counter = $db->fetch_array($query))
 589                      {
 590                          $user_counters[$counter['uid']]['num_posts'] += $counter['posts'];
 591                      }
 592                  }
 593  
 594                  if($thread['visible'] == 1 && $forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|')
 595                  {
 596                      ++$user_counters[$thread['uid']]['num_threads'];
 597                  }
 598  
 599              }
 600              $posts_to_unapprove[] = $thread['firstpost'];
 601          }
 602  
 603          $approve = array(
 604              "visible" => 0
 605          );
 606          $db->update_query("threads", $approve, "tid IN ($tid_list)");
 607          // Unapprove redirects, too
 608          $redirect_tids = array();
 609          $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})");
 610          while($redirect_tid = $db->fetch_field($query, 'tid'))
 611          {
 612              $redirect_tids[] = $redirect_tid;
 613          }
 614          if(!empty($redirect_tids))
 615          {
 616              $this->unapprove_threads($redirect_tids);
 617          }
 618          if(!empty($posts_to_unapprove))
 619          {
 620              $db->update_query("posts", $approve, "pid IN (".implode(',', $posts_to_unapprove).")");
 621          }
 622  
 623          $plugins->run_hooks("class_moderation_unapprove_threads", $tids);
 624  
 625          if(!empty($forum_counters))
 626          {
 627              foreach($forum_counters as $fid => $counters)
 628              {
 629                  // Update stats
 630                  $update_array = array(
 631                      "threads" => "-{$counters['num_threads']}",
 632                      "unapprovedthreads" => "+{$counters['num_unapprovedthreads']}",
 633                      "posts" => "-{$counters['num_posts']}",
 634                      "unapprovedposts" => "+{$counters['num_unapprovedposts']}",
 635                      "deletedthreads" => "-{$counters['num_deletedthreads']}",
 636                      "deletedposts" => "-{$counters['num_deletedposts']}"
 637                  );
 638                  update_forum_counters($fid, $update_array);
 639                  update_forum_lastpost($fid);
 640              }
 641          }
 642  
 643          if(!empty($user_counters))
 644          {
 645              foreach($user_counters as $uid => $counters)
 646              {
 647                  $update_array = array(
 648                      "postnum" => "-{$counters['num_posts']}",
 649                      "threadnum" => "-{$counters['num_threads']}",
 650                  );
 651                  update_user_counters($uid, $update_array);
 652              }
 653          }
 654  
 655          return true;
 656      }
 657  
 658      /**
 659       * Delete a specific post
 660       *
 661       * @param int $pid Post ID
 662       * @return boolean
 663       */
 664  	function delete_post($pid)
 665      {
 666          global $db, $cache, $plugins;
 667  
 668          $pid = $plugins->run_hooks("class_moderation_delete_post_start", $pid);
 669          // Get pid, uid, fid, tid, visibility, forum post count status of post
 670          $pid = (int)$pid;
 671          $query = $db->query("
 672              SELECT p.pid, p.uid, p.fid, p.tid, p.visible, t.visible as threadvisible
 673              FROM ".TABLE_PREFIX."posts p
 674              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
 675              WHERE p.pid='$pid'
 676          ");
 677          $post = $db->fetch_array($query);
 678          if(!$post)
 679          {
 680              return false;
 681          }
 682  
 683          $forum = get_forum($post['fid']);
 684          // If post counts enabled in this forum and it hasn't already been unapproved, remove 1
 685          if($forum['usepostcounts'] != 0 && $post['visible'] != -1 && $post['visible'] != 0 && $post['threadvisible'] != 0 && $post['threadvisible'] != -1)
 686          {
 687              update_user_counters($post['uid'], array('postnum' => "-1"));
 688          }
 689  
 690          if(!function_exists("remove_attachments"))
 691          {
 692              require  MYBB_ROOT."inc/functions_upload.php";
 693          }
 694  
 695          // Remove attachments
 696          remove_attachments($pid);
 697  
 698          // Delete the post
 699          $db->delete_query("posts", "pid='$pid'");
 700  
 701          // Remove any reports attached to this post
 702          $db->delete_query("reportedcontent", "id='{$pid}' AND (type = 'post' OR type = '')");
 703  
 704          // Update unapproved post count
 705          if($post['visible'] == 0)
 706          {
 707              $update_array = array(
 708                  "unapprovedposts" => "-1"
 709              );
 710          }
 711          elseif($post['visible'] == -1)
 712          {
 713              $update_array = array(
 714                  "deletedposts" => "-1"
 715              );
 716          }
 717          else
 718          {
 719              $update_array = array(
 720                  "replies" => "-1"
 721              );
 722          }
 723  
 724          $plugins->run_hooks("class_moderation_delete_post", $post['pid']);
 725  
 726          update_thread_counters($post['tid'], $update_array);
 727          update_last_post($post['tid']);
 728  
 729          // Update unapproved post count
 730          if(($post['visible'] == 0 && $post['threadvisible'] != -1) || $post['threadvisible'] == 0)
 731          {
 732              $update_array = array(
 733                  "unapprovedposts" => "-1"
 734              );
 735          }
 736          elseif($post['visible'] == -1 || $post['threadvisible'] == -1)
 737          {
 738              $update_array = array(
 739                  "deletedposts" => "-1"
 740              );
 741          }
 742          else
 743          {
 744              $update_array = array(
 745                  "posts" => "-1"
 746              );
 747          }
 748  
 749          update_forum_counters($post['fid'], $update_array);
 750          update_forum_lastpost($post['fid']);
 751  
 752          return true;
 753      }
 754  
 755      /**
 756       * Merge posts within thread
 757       *
 758       * @param array $pids Post IDs to be merged
 759       * @param int $tid Thread ID (Set to 0 if posts from multiple threads are selected)
 760       * @return int ID of the post into which all other posts are merged
 761       */
 762  	function merge_posts($pids=array(), $tid=0, $sep="new_line")
 763      {
 764          global $db, $plugins;
 765  
 766          // Make sure we only have valid values
 767          $pids = array_map('intval', $pids);
 768  
 769          if(empty($pids) || count($pids) < 2)
 770          {
 771              return false;
 772          }
 773  
 774          $pidin = implode(',', $pids);
 775          $attachment_count = 0;
 776  
 777          $first = 1;
 778          // Get the messages to be merged
 779          $query = $db->query("
 780              SELECT p.pid, p.uid, p.fid, p.tid, p.visible, p.message, t.visible AS threadvisible, t.replies AS threadreplies, t.firstpost AS threadfirstpost, t.unapprovedposts AS threadunapprovedposts, COUNT(a.aid) AS attachmentcount
 781              FROM ".TABLE_PREFIX."posts p
 782              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
 783              LEFT JOIN ".TABLE_PREFIX."attachments a ON (a.pid=p.pid AND a.visible=1)
 784              WHERE p.pid IN($pidin)
 785              GROUP BY p.pid
 786              ORDER BY p.dateline ASC, p.pid ASC
 787          ");
 788          $message = '';
 789          $threads = $forum_counters = $thread_counters = $user_counters = array();
 790          while($post = $db->fetch_array($query))
 791          {
 792              $threads[$post['tid']] = $post['tid'];
 793              if(!isset($thread_counters[$post['tid']]))
 794              {
 795                  $thread_counters[$post['tid']] = array(
 796                      'replies' => 0,
 797                      'unapprovedposts' => 0,
 798                      'deletedposts' => 0,
 799                      'attachmentcount' => 0
 800                  );
 801              }
 802              if($first == 1)
 803              { // all posts will be merged into this one
 804                  $masterpid = $post['pid'];
 805                  $message = $post['message'];
 806                  $fid = $post['fid'];
 807                  $mastertid = $post['tid'];
 808                  $first = 0;
 809                  $visible = $post['visible'];
 810              }
 811              else
 812              {
 813                   // these are the selected posts
 814                  if($sep == "new_line")
 815                  {
 816                      $message .= "\n\n {$post['message']}";
 817                  }
 818                  else
 819                  {
 820                      $message .= "[hr]{$post['message']}";
 821                  }
 822  
 823                  if(!isset($forum_counters[$post['fid']]))
 824                  {
 825                      $forum_counters[$post['fid']] = array(
 826                          'num_posts' => 0,
 827                          'unapprovedposts' => 0,
 828                          'deletedposts' => 0
 829                      );
 830                  }
 831  
 832                  if($post['visible'] == 1)
 833                  {
 834                      --$thread_counters[$post['tid']]['replies'];
 835                      $forum = get_forum($post['fid']);
 836                      if(!isset($user_counters[$post['uid']]))
 837                      {
 838                          $user_counters[$post['uid']] = array(
 839                              'num_posts' => 0,
 840                              'num_threads' => 0
 841                          );
 842                      }
 843                      // Subtract 1 from user's post count
 844                      if($forum['usepostcounts'] != 0 && $post['threadvisible'] == 1)
 845                      {
 846                          // Update post count of the user of the merged posts
 847                          --$user_counters[$post['uid']]['num_posts'];
 848                      }
 849                      if($post['threadfirstpost'] == $post['pid'] && $forum['usethreadcounts'] != 0 && $post['threadvisible'] == 1)
 850                      {
 851                          --$user_counters[$post['uid']]['num_threads'];
 852                      }
 853                      $thread_counters[$post['tid']]['attachmentcount'] -= $post['attachmentcount'];
 854                  }
 855                  elseif($post['visible'] == 0)
 856                  {
 857                      // Subtract 1 unapproved post from post's thread
 858                      --$thread_counters[$post['tid']]['unapprovedposts'];
 859                  }
 860                  elseif($post['visible'] == -1)
 861                  {
 862                      // Subtract 1 deleted post from post's thread
 863                      --$thread_counters[$post['tid']]['deletedposts'];
 864                  }
 865  
 866                  // Subtract 1 post from post's forum
 867                  if($post['threadvisible'] == 1 && $post['visible'] == 1)
 868                  {
 869                      --$forum_counters[$post['fid']]['num_posts'];
 870                  }
 871                  elseif($post['threadvisible'] == 0 || ($post['visible'] == 0 && $post['threadvisible'] != -1))
 872                  {
 873                      --$forum_counters[$post['fid']]['unapprovedposts'];
 874                  }
 875                  else
 876                  {
 877                      --$forum_counters[$post['fid']]['deletedposts'];
 878                  }
 879  
 880                  // Add attachment count to thread
 881                  if($visible == 1)
 882                  {
 883                      $thread_counters[$mastertid]['attachmentcount'] += $post['attachmentcount'];
 884                  }
 885              }
 886          }
 887  
 888          // Update the message
 889          $mergepost = array(
 890              "message" => $db->escape_string($message),
 891          );
 892          $db->update_query("posts", $mergepost, "pid = '{$masterpid}'");
 893  
 894          // Delete the extra posts
 895          $db->delete_query("posts", "pid IN({$pidin}) AND pid != '{$masterpid}'");
 896  
 897          // Update pid for attachments
 898          $mergepost2 = array(
 899              "pid" => $masterpid,
 900          );
 901          $db->update_query("attachments", $mergepost2, "pid IN({$pidin})");
 902  
 903          // If the first post of a thread is merged out, the first should be updated
 904          $query = $db->simple_select("threads", "tid, uid, fid, visible", "firstpost IN({$pidin}) AND firstpost != '{$masterpid}'");
 905          while($thread = $db->fetch_array($query))
 906          {
 907              // In some cases the first post of a thread changes
 908              // Therefore resync the visible field to make sure they're the same if they're not
 909              $query = $db->simple_select("posts", "pid, uid, visible", "tid='{$thread['tid']}'", array('order_by' => 'dateline, pid', 'limit' => 1));
 910              $new_firstpost = $db->fetch_array($query);
 911              if($thread['visible'] != $new_firstpost['visible'])
 912              {
 913                  $db->update_query("posts", array('visible' => $thread['visible']), "pid='{$new_firstpost['pid']}'");
 914                  // Correct counters
 915                  if($new_firstpost['visible'] == 1)
 916                  {
 917                      --$thread_counters[$thread['tid']]['replies'];
 918                  }
 919                  elseif($new_firstpost['visible'] == -1)
 920                  {
 921                      --$thread_counters[$thread['tid']]['deletedposts'];
 922                  }
 923                  else
 924                  {
 925                      --$thread_counters[$thread['tid']]['unapprovedposts'];
 926                  }
 927                  if($thread['visible'] == 1)
 928                  {
 929                      ++$thread_counters[$thread['tid']]['replies'];
 930                  }
 931                  elseif($thread['visible'] == -1)
 932                  {
 933                      ++$thread_counters[$thread['tid']]['deletedposts'];
 934                  }
 935                  else
 936                  {
 937                      ++$thread_counters[$thread['tid']]['unapprovedposts'];
 938                  }
 939              }
 940  
 941              if($new_firstpost['uid'] != $thread['uid'] && $forum['usethreadcounts'] != 0 && $thread['visible'] == 1)
 942              {
 943                  if(!isset($user_counters[$new_firstpost['uid']]))
 944                  {
 945                      $user_counters[$new_firstpost['uid']] = array(
 946                          'num_posts' => 0,
 947                          'num_threads' => 0
 948                      );
 949                  }
 950                  ++$user_counters[$new_firstpost['uid']]['num_threads'];
 951              }
 952              update_first_post($thread['tid']);
 953          }
 954  
 955          $arguments = array("pids" => $pids, "tid" => $tid);
 956          $plugins->run_hooks("class_moderation_merge_posts", $arguments);
 957  
 958          if(!empty($thread_counters))
 959          {
 960              foreach($thread_counters as $tid => $counters)
 961              {
 962                  $counters = array(
 963                      'replies' => signed($counters['replies']),
 964                      'unapprovedposts' => signed($counters['unapprovedposts']),
 965                      'deletedposts' => signed($counters['deletedposts']),
 966                      'attachmentcount' => signed($counters['attachmentcount'])
 967                  );
 968                  update_thread_counters($tid, $counters);
 969                  update_last_post($tid);
 970              }
 971          }
 972  
 973          if(!empty($forum_counters))
 974          {
 975              foreach($forum_counters as $fid => $counters)
 976              {
 977                  $updated_forum_stats = array(
 978                      'posts' => signed($counters['num_posts']),
 979                      'unapprovedposts' => signed($counters['unapprovedposts']),
 980                      'deletedposts' => signed($counters['deletedposts'])
 981                  );
 982                  update_forum_counters($fid, $updated_forum_stats);
 983                  update_forum_lastpost($fid);
 984              }
 985          }
 986  
 987          if(!empty($user_counters))
 988          {
 989              foreach($user_counters as $uid => $counters)
 990              {
 991                  $update_array = array(
 992                      "postnum" => "+{$counters['num_posts']}",
 993                      "threadnum" => "+{$counters['num_threads']}"
 994                  );
 995                  update_user_counters($uid, $update_array);
 996              }
 997          }
 998  
 999          return $masterpid;
1000      }
1001  
1002      /**
1003       * Move/copy thread
1004       *
1005       * @param int $tid Thread to be moved
1006       * @param int $new_fid Destination forum
1007       * @param string $method Method of movement (redirect, copy, move)
1008       * @param int $redirect_expire Expiry timestamp for redirect
1009       * @return int Thread ID
1010       */
1011  	function move_thread($tid, $new_fid, $method="redirect", $redirect_expire=0)
1012      {
1013          global $db, $plugins;
1014  
1015          // Get thread info
1016          $tid = (int)$tid;
1017          $new_fid = (int)$new_fid;
1018          $redirect_expire = (int)$redirect_expire;
1019  
1020          $thread = get_thread($tid, true);
1021  
1022          $newforum = get_forum($new_fid);
1023          if(!$thread || !$newforum)
1024          {
1025              return false;
1026          }
1027          $fid = $thread['fid'];
1028          $forum = get_forum($fid);
1029  
1030          $num_threads = $num_unapproved_threads = $num_posts = $num_unapproved_posts = $num_deleted_posts = $num_deleted_threads = 0;
1031  
1032          if($thread['visible'] == 1)
1033          {
1034              $num_threads++;
1035              $num_posts = $thread['replies']+1;
1036              $num_unapproved_posts = $thread['unapprovedposts'];
1037              $num_deleted_posts = $thread['deletedposts'];
1038          }
1039          elseif($thread['visible'] == -1)
1040          {
1041              $num_deleted_threads++;
1042              // Implied forum deleted count for deleted threads
1043              $num_deleted_posts = $thread['replies']+$thread['deletedposts']+$thread['unapprovedposts']+1;
1044          }
1045          else
1046          {
1047              $num_unapproved_threads++;
1048              // Implied forum unapproved count for unapproved threads
1049              $num_unapproved_posts = $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1;
1050          }
1051  
1052          switch($method)
1053          {
1054              case "redirect": // move (and leave redirect) thread
1055                  $arguments = array("tid" => $tid, "new_fid" => $new_fid);
1056                  $plugins->run_hooks("class_moderation_move_thread_redirect", $arguments);
1057  
1058                  $query = $db->simple_select('threads', 'tid', "closed='moved|$tid' AND fid='$new_fid'");
1059                  while($redirect_tid = $db->fetch_field($query, 'tid'))
1060                  {
1061                      $this->delete_thread($redirect_tid);
1062                  }
1063                  $changefid = array(
1064                      "fid" => $new_fid,
1065                  );
1066                  $db->update_query("threads", $changefid, "tid='$tid'");
1067                  $db->update_query("posts", $changefid, "tid='$tid'");
1068  
1069                  // If the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix
1070                  if($thread['prefix'] != 0)
1071                  {
1072                      switch($db->type)
1073                      {
1074                          case "pgsql":
1075                          case "sqlite":
1076                              $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'");
1077                              break;
1078                          default:
1079                              $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'");
1080                      }
1081                      if($db->fetch_field($query, "num_prefixes") == 0)
1082                      {
1083                          $sqlarray = array(
1084                              "prefix" => 0,
1085                          );
1086                          $db->update_query("threads", $sqlarray, "tid='$tid'");
1087                      }
1088                  }
1089  
1090                  $threadarray = array(
1091                      "fid" => $thread['fid'],
1092                      "subject" => $db->escape_string($thread['subject']),
1093                      "icon" => $thread['icon'],
1094                      "uid" => $thread['uid'],
1095                      "username" => $db->escape_string($thread['username']),
1096                      "dateline" => $thread['dateline'],
1097                      "lastpost" => $thread['lastpost'],
1098                      "lastposteruid" => $thread['lastposteruid'],
1099                      "lastposter" => $db->escape_string($thread['lastposter']),
1100                      "views" => 0,
1101                      "replies" => 0,
1102                      "closed" => "moved|$tid",
1103                      "sticky" => $thread['sticky'],
1104                      "visible" => (int)$thread['visible'],
1105                      "notes" => ''
1106                  );
1107                  $redirect_tid = $db->insert_query("threads", $threadarray);
1108                  if($redirect_expire)
1109                  {
1110                      $this->expire_thread($redirect_tid, $redirect_expire);
1111                  }
1112  
1113                  // If we're moving back to a forum where we left a redirect, delete the rediect
1114                  $query = $db->simple_select("threads", "tid", "closed LIKE 'moved|".(int)$tid."' AND fid='".(int)$new_fid."'");
1115                  while($redirect_tid = $db->fetch_field($query, 'tid'))
1116                  {
1117                      $this->delete_thread($redirect_tid);
1118                  }
1119                   break;
1120              case "copy":// copy thread
1121  
1122                  $threadarray = array(
1123                      "fid" => $new_fid,
1124                      "subject" => $db->escape_string($thread['subject']),
1125                      "icon" => $thread['icon'],
1126                      "uid" => $thread['uid'],
1127                      "username" => $db->escape_string($thread['username']),
1128                      "dateline" => $thread['dateline'],
1129                      "firstpost" => 0,
1130                      "lastpost" => $thread['lastpost'],
1131                      "lastposteruid" => $thread['lastposteruid'],
1132                      "lastposter" => $db->escape_string($thread['lastposter']),
1133                      "views" => $thread['views'],
1134                      "replies" => $thread['replies'],
1135                      "closed" => $thread['closed'],
1136                      "sticky" => $thread['sticky'],
1137                      "visible" => (int)$thread['visible'],
1138                      "unapprovedposts" => $thread['unapprovedposts'],
1139                      "deletedposts" => $thread['deletedposts'],
1140                      "attachmentcount" => $thread['attachmentcount'],
1141                      "prefix" => $thread['prefix'],
1142                      "notes" => ''
1143                  );
1144  
1145                  $arguments = array("tid" => $tid, "new_fid" => $new_fid);
1146                  $plugins->run_hooks("class_moderation_copy_thread", $arguments);
1147  
1148                  // If the thread has a prefix and the destination forum doesn't accept that prefix, don't copy the prefix
1149                  if($threadarray['prefix'] != 0)
1150                  {
1151                      switch($db->type)
1152                      {
1153                          case "pgsql":
1154                          case "sqlite":
1155                              $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'");
1156                              break;
1157                          default:
1158                              $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'");
1159                      }
1160                      if($db->fetch_field($query, "num_prefixes") == 0)
1161                      {
1162                          $threadarray['prefix'] = 0;
1163                      }
1164                  }
1165  
1166                  $newtid = $db->insert_query("threads", $threadarray);
1167  
1168                  if($thread['poll'] != 0)
1169                  {
1170                      $query = $db->simple_select("polls", "*", "tid = '{$thread['tid']}'");
1171                      $poll = $db->fetch_array($query);
1172  
1173                      $poll_array = array(
1174                          'tid' => $newtid,
1175                          'question' => $db->escape_string($poll['question']),
1176                          'dateline' => $poll['dateline'],
1177                          'options' => $db->escape_string($poll['options']),
1178                          'votes' => $db->escape_string($poll['votes']),
1179                          'numoptions' => $poll['numoptions'],
1180                          'numvotes' => $poll['numvotes'],
1181                          'timeout' => $poll['timeout'],
1182                          'closed' => $poll['closed'],
1183                          'multiple' => $poll['multiple'],
1184                          'public' => $poll['public']
1185                      );
1186                      $new_pid = $db->insert_query("polls", $poll_array);
1187  
1188                      $query = $db->simple_select("pollvotes", "*", "pid = '{$poll['pid']}'");
1189                      while($pollvote = $db->fetch_array($query))
1190                      {
1191                          $pollvote_array = array(
1192                              'pid' => $new_pid,
1193                              'uid' => $pollvote['uid'],
1194                              'voteoption' => $pollvote['voteoption'],
1195                              'dateline' => $pollvote['dateline'],
1196                          );
1197                          $db->insert_query("pollvotes", $pollvote_array);
1198                      }
1199  
1200                      $db->update_query("threads", array('poll' => $new_pid), "tid='{$newtid}'");
1201                  }
1202  
1203                  $query = $db->simple_select("posts", "*", "tid = '{$thread['tid']}'");
1204                  while($post = $db->fetch_array($query))
1205                  {
1206                      $post_array = array(
1207                          'tid' => $newtid,
1208                          'fid' => $new_fid,
1209                          'subject' => $db->escape_string($post['subject']),
1210                          'icon' => $post['icon'],
1211                          'uid' => $post['uid'],
1212                          'username' => $db->escape_string($post['username']),
1213                          'dateline' => $post['dateline'],
1214                          'ipaddress' => $db->escape_binary($post['ipaddress']),
1215                          'includesig' => $post['includesig'],
1216                          'smilieoff' => $post['smilieoff'],
1217                          'edituid' => $post['edituid'],
1218                          'edittime' => $post['edittime'],
1219                          'visible' => $post['visible'],
1220                          'message' => $db->escape_string($post['message']),
1221                      );
1222                      $pid = $db->insert_query("posts", $post_array);
1223  
1224                      // Properly set our new firstpost in our new thread
1225                      if($thread['firstpost'] == $post['pid'])
1226                      {
1227                          $db->update_query("threads", array('firstpost' => $pid), "tid='{$newtid}'");
1228                      }
1229  
1230                      // Insert attachments for this post
1231                      $query2 = $db->simple_select("attachments", "*", "pid = '{$post['pid']}'");
1232                      while($attachment = $db->fetch_array($query2))
1233                      {
1234                          $attachment_array = array(
1235                              'pid' => $pid,
1236                              'uid' => $attachment['uid'],
1237                              'filename' => $db->escape_string($attachment['filename']),
1238                              'filetype' => $db->escape_string($attachment['filetype']),
1239                              'filesize' => $attachment['filesize'],
1240                              'attachname' => $db->escape_string($attachment['attachname']),
1241                              'downloads' => $attachment['downloads'],
1242                              'visible' => $attachment['visible'],
1243                              'thumbnail' => $db->escape_string($attachment['thumbnail'])
1244                          );
1245                          $new_aid = $db->insert_query("attachments", $attachment_array);
1246  
1247                          $post['message'] = str_replace("[attachment={$attachment['aid']}]", "[attachment={$new_aid}]", $post['message']);
1248                      }
1249  
1250                      if(strpos($post['message'], "[attachment=") !== false)
1251                      {
1252                          $db->update_query("posts", array('message' => $db->escape_string($post['message'])), "pid='{$pid}'");
1253                      }
1254                  }
1255  
1256                  update_thread_data($newtid);
1257  
1258                  $the_thread = $newtid;
1259                  break;
1260              default:
1261              case "move": // plain move thread
1262                  $arguments = array("tid" => $tid, "new_fid" => $new_fid);
1263                  $plugins->run_hooks("class_moderation_move_simple", $arguments);
1264  
1265                  $sqlarray = array(
1266                      "fid" => $new_fid,
1267                  );
1268                  $db->update_query("threads", $sqlarray, "tid='$tid'");
1269                  $db->update_query("posts", $sqlarray, "tid='$tid'");
1270  
1271                  // If the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix
1272                  if($thread['prefix'] != 0)
1273                  {
1274                      switch($db->type)
1275                      {
1276                          case "pgsql":
1277                          case "sqlite":
1278                              $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'");
1279                              break;
1280                          default:
1281                              $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'");
1282                      }
1283                      if($db->fetch_field($query, "num_prefixes") == 0)
1284                      {
1285                          $sqlarray = array(
1286                              "prefix" => 0,
1287                          );
1288                          $db->update_query("threads", $sqlarray, "tid='$tid'");
1289                      }
1290                  }
1291  
1292                  // If we're moving back to a forum where we left a redirect, delete the rediect
1293                  $query = $db->simple_select("threads", "tid", "closed LIKE 'moved|".(int)$tid."' AND fid='".(int)$new_fid."'");
1294                  while($redirect_tid = $db->fetch_field($query, 'tid'))
1295                  {
1296                      $this->delete_thread($redirect_tid);
1297                  }
1298                  break;
1299          }
1300  
1301          // Do post and thread count changes if changing between countable and non-countable forums
1302          $query = $db->query("
1303              SELECT COUNT(p.pid) AS posts, u.uid
1304              FROM ".TABLE_PREFIX."posts p
1305              LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid)
1306              WHERE p.tid='$tid' AND p.visible=1
1307              GROUP BY u.uid
1308              ORDER BY posts DESC
1309          ");
1310          while($posters = $db->fetch_array($query))
1311          {
1312              $pcount = 0;
1313              if($forum['usepostcounts'] == 1 && $method != 'copy' && $newforum['usepostcounts'] == 0 && $thread['visible'] == 1)
1314              {
1315                  $pcount -= $posters['posts'];
1316              }
1317              if(($forum['usepostcounts'] == 0 || $method == 'copy') && $newforum['usepostcounts'] == 1 && $thread['visible'] == 1)
1318              {
1319                  $pcount += $posters['posts'];
1320              }
1321  
1322              if($pcount > 0)
1323              {
1324                  update_user_counters($posters['uid'], array('postnum' => "+$pcount"));
1325              }
1326              elseif($pcount < 0)
1327              {
1328                  update_user_counters($posters['uid'], array('postnum' => $pcount));
1329              }
1330          }
1331  
1332          if($forum['usethreadcounts'] == 1 && $method != 'copy' && $newforum['usethreadcounts'] == 0 && $thread['visible'] == 1)
1333          {
1334              update_user_counters($thread['uid'], array('threadnum' => "-1"));
1335          }
1336          elseif(($forum['usethreadcounts'] == 0 || $method == 'copy') && $newforum['usethreadcounts'] == 1 && $thread['visible'] == 1)
1337          {
1338              update_user_counters($thread['uid'], array('threadnum' => "+1"));
1339          }
1340  
1341          // Update forum counts
1342          $update_array = array(
1343              "threads" => "+{$num_threads}",
1344              "unapprovedthreads" => "+{$num_unapproved_threads}",
1345              "posts" => "+{$num_posts}",
1346              "unapprovedposts" => "+{$num_unapproved_posts}",
1347              "deletedthreads" => "+{$num_deleted_threads}",
1348              "deletedposts" => "+{$num_deleted_posts}"
1349          );
1350          update_forum_counters($new_fid, $update_array);
1351          update_forum_lastpost($new_fid);
1352  
1353          if($method != "copy")
1354          {
1355              // The redirect needs to be counted, too
1356              if($method == "redirect")
1357              {
1358                  if($thread['visible'] == -1)
1359                  {
1360                      --$num_deleted_threads;
1361                      --$num_deleted_posts;
1362                  }
1363                  elseif($thread['visible'] == 0)
1364                  {
1365                      --$num_unapproved_threads;
1366                      --$num_unapproved_posts;
1367                  }
1368                  else
1369                  {
1370                      --$num_threads;
1371                      --$num_posts;
1372                  }
1373              }
1374              $update_array = array(
1375                  "threads" => "-{$num_threads}",
1376                  "unapprovedthreads" => "-{$num_unapproved_threads}",
1377                  "posts" => "-{$num_posts}",
1378                  "unapprovedposts" => "-{$num_unapproved_posts}",
1379                  "deletedthreads" => "-{$num_deleted_threads}",
1380                  "deletedposts" => "-{$num_deleted_posts}"
1381              );
1382              update_forum_counters($fid, $update_array);
1383              update_forum_lastpost($fid);
1384          }
1385  
1386          if(isset($newtid))
1387          {
1388              return $newtid;
1389          }
1390          else
1391          {
1392              // Remove thread subscriptions for the users who no longer have permission to view the thread
1393              $this->remove_thread_subscriptions($tid, false, $new_fid);
1394  
1395              return $tid;
1396          }
1397      }
1398  
1399      /**
1400       * Merge one thread into another
1401       *
1402       * @param int $mergetid Thread that will be merged into destination
1403       * @param int $tid Destination thread
1404       * @param string $subject New thread subject
1405       * @return boolean
1406       */
1407  	function merge_threads($mergetid, $tid, $subject)
1408      {
1409          global $db, $mybb, $mergethread, $thread, $plugins, $cache;
1410  
1411          $mergetid = (int)$mergetid;
1412          $tid = (int)$tid;
1413  
1414          if(!isset($mergethread['tid']) || $mergethread['tid'] != $mergetid)
1415          {
1416              $mergethread = get_thread($mergetid);
1417          }
1418          if(!isset($thread['tid']) || $thread['tid'] != $tid)
1419          {
1420              $thread = get_thread($tid);
1421          }
1422  
1423          if(!$mergethread || !$thread)
1424          {
1425              return false;
1426          }
1427  
1428          $forum_cache = $cache->read('forums');
1429  
1430          $threadarray = array();
1431          if(!$thread['poll'] && $mergethread['poll'])
1432          {
1433              $threadarray['poll'] = $mergethread['poll'];
1434              $sqlarray = array(
1435                  "tid" => $tid,
1436              );
1437              $db->update_query("polls", $sqlarray, "tid='".(int)$mergethread['tid']."'");
1438          }
1439          // Both the old and the new thread have polls? Remove one
1440          elseif($mergethread['poll'])
1441          {
1442              $db->delete_query("polls", "pid='{$mergethread['poll']}'");
1443              $db->delete_query("pollvotes", "pid='{$mergethread['poll']}'");
1444          }
1445  
1446          $subject = $db->escape_string($subject);
1447          $threadarray['subject'] = $subject;
1448  
1449          $user_posts = array();
1450          if($thread['visible'] != $mergethread['visible'] || $forum_cache[$thread['fid']]['usepostcounts'] != $forum_cache[$mergethread['fid']]['usepostcounts'])
1451          {
1452              $query = $db->query("
1453                  SELECT uid, COUNT(pid) AS postnum
1454                  FROM ".TABLE_PREFIX."posts
1455                  WHERE tid='{$mergetid}' AND visible=1
1456                  GROUP BY uid
1457              ");
1458              while($post = $db->fetch_array($query))
1459              {
1460                  // Update user counters
1461                  if($mergethread['visible'] == 1 && $forum_cache[$mergethread['fid']]['usepostcounts'] == 1)
1462                  {
1463                      $user_posts[$post['uid']]['postnum'] -= $post['postnum'];
1464                  }
1465                  elseif($thread['visible'] == 1 && $forum_cache[$thread['fid']]['usepostcounts'] == 1)
1466                  {
1467                      $user_posts[$post['uid']]['postnum'] += $post['postnum'];
1468                  }
1469              }
1470          }
1471  
1472          $sqlarray = array(
1473              "tid" => $tid,
1474              "fid" => $thread['fid'],
1475              "replyto" => 0,
1476          );
1477          $db->update_query("posts", $sqlarray, "tid='{$mergetid}'");
1478  
1479          $sqlarray = array(
1480              "closed" => "moved|{$tid}",
1481          );
1482          $db->update_query("threads", $sqlarray, "closed='moved|{$mergetid}'");
1483          $sqlarray = array(
1484              "tid" => $tid,
1485          );
1486  
1487          // Update the thread ratings
1488          $new_numrating = $thread['numratings'] + $mergethread['numratings'];
1489          $new_threadrating = $thread['totalratings'] + $mergethread['totalratings'];
1490  
1491          $threadarray["numratings"] = $new_numrating;
1492          $threadarray["totalratings"] = $new_threadrating;
1493          $db->update_query("threads", $threadarray, "tid = '{$tid}'");
1494  
1495          // Check if we have a thread subscription already for our new thread
1496          $subscriptions = array();
1497  
1498          $query = $db->simple_select("threadsubscriptions", "tid, uid", "tid='{$mergetid}' OR tid='{$tid}'");
1499          while($subscription = $db->fetch_array($query))
1500          {
1501              if(!isset($subscriptions[$subscription['tid']]))
1502              {
1503                  $subscriptions[$subscription['tid']] = array();
1504              }
1505              $subscriptions[$subscription['tid']][] = $subscription['uid'];
1506          }
1507  
1508          // Update any subscriptions for the merged thread
1509          if(!empty($subscriptions[$mergetid]))
1510           {
1511              $update_users = array();
1512              foreach($subscriptions[$mergetid] as $user)
1513              {
1514                  if(!isset($subscriptions[$tid]) || !in_array($user, $subscriptions[$tid]))
1515                  {
1516                      // User doesn't have a $tid subscription
1517                      $update_users[] = $user;
1518                  }
1519              }
1520  
1521              if(!empty($update_users))
1522              {
1523                  $update_array = array(
1524                      "tid" => $tid
1525                  );
1526  
1527                  $update_users = implode(",", $update_users);
1528                  $db->update_query("threadsubscriptions", $update_array, "tid = '{$mergetid}' AND uid IN ({$update_users})");
1529              }
1530           }
1531  
1532          // Remove source thread subscriptions
1533          $db->delete_query("threadsubscriptions", "tid = '{$mergetid}'");
1534  
1535          $arguments = array("mergetid" => $mergetid, "tid" => $tid, "subject" => $subject);
1536          $plugins->run_hooks("class_moderation_merge_threads", $arguments);
1537  
1538          $this->delete_thread($mergetid);
1539  
1540          // Add the former first post
1541          if($mergethread['visible'] == 1)
1542          {
1543              ++$mergethread['replies'];
1544          }
1545          elseif($mergethread['visible'] == -1)
1546          {
1547              ++$mergethread['deletedposts'];
1548          }
1549          else
1550          {
1551              ++$mergethread['unapprovedposts'];
1552          }
1553  
1554          // In some cases the thread we may be merging with may cause us to have a new firstpost if it is an older thread
1555          // Therefore resync the visible field to make sure they're the same if they're not
1556          $query = $db->simple_select("posts", "pid, uid, visible", "tid='{$tid}'", array('order_by' => 'dateline, pid', 'limit' => 1));
1557          $new_firstpost = $db->fetch_array($query);
1558          if($thread['visible'] != $new_firstpost['visible'])
1559          {
1560              $db->update_query("posts", array('visible' => $thread['visible']), "pid='{$new_firstpost['pid']}'");
1561              if($new_firstpost['visible'] == 1 && $forum_cache[$thread['fid']]['usepostcounts'] == 1)
1562              {
1563                  --$user_posts[$post['uid']]['postnum'];
1564              }
1565              elseif($thread['visible'] == 1 && $forum_cache[$thread['fid']]['usepostcounts'] == 1)
1566              {
1567                  ++$user_posts[$post['uid']]['postnum'];
1568              }
1569          }
1570          // Update first post if needed
1571          if($new_firstpost['pid'] != $thread['firstpost'])
1572          {
1573              update_first_post($thread['tid']);
1574          }
1575  
1576          // Update thread count if thread has a new firstpost and is visible
1577          if($thread['uid'] != $new_firstpost['uid'] && $thread['visible'] == 1 && $forum_cache[$thread['fid']]['usethreadcounts'] == 1)
1578          {
1579              if(!isset($user_posts[$thread['uid']]['threadnum']))
1580              {
1581                  $user_posts[$thread['uid']]['threadnum'] = 0;
1582              }
1583              --$user_posts[$thread['uid']]['threadnum'];
1584              if(!isset($user_posts[$new_firstpost['uid']]['threadnum']))
1585              {
1586                  $user_posts[$new_firstpost['uid']]['threadnum'] = 0;
1587              }
1588              ++$user_posts[$new_firstpost['uid']]['threadnum'];
1589          }
1590  
1591          // Thread is not in current forum
1592          if($mergethread['fid'] != $thread['fid'])
1593          {
1594              // If new thread is unapproved, implied counter comes in to effect
1595              if($thread['visible'] == 0)
1596              {
1597                  $updated_stats = array(
1598                      "unapprovedposts" => '+'.($mergethread['replies']+$mergethread['unapprovedposts']+$mergethread['deletedposts'])
1599                  );
1600              }
1601              elseif($thread['visible'] == -1)
1602              {
1603                  $updated_stats = array(
1604                      "deletedposts" => '+'.($mergethread['replies']+$mergethread['deletedposts']+$mergethread['unapprovedposts'])
1605                  );
1606              }
1607              else
1608              {
1609                  $updated_stats = array(
1610                      "posts" => "+{$mergethread['replies']}",
1611                      "unapprovedposts" => "+{$mergethread['unapprovedposts']}",
1612                      "deletedposts" => "+{$mergethread['deletedposts']}"
1613                  );
1614              }
1615              update_forum_counters($thread['fid'], $updated_stats);
1616  
1617              // If old thread is unapproved, implied counter comes in to effect
1618              if($mergethread['visible'] == 0)
1619              {
1620                  $updated_stats = array(
1621                      "unapprovedposts" => '-'.($mergethread['replies']+$mergethread['unapprovedposts']+$mergethread['deletedposts'])
1622                  );
1623              }
1624              elseif($mergethread['visible'] == -1)
1625              {
1626                  $updated_stats = array(
1627                      "deletedposts" => '-'.($mergethread['replies']+$mergethread['deletedposts']+$mergethread['unapprovedposts'])
1628                  );
1629              }
1630              else
1631              {
1632                  $updated_stats = array(
1633                      "posts" => "-{$mergethread['replies']}",
1634                      "unapprovedposts" => "-{$mergethread['unapprovedposts']}",
1635                      "deletedposts" => "-{$mergethread['deletedposts']}"
1636                  );
1637              }
1638              update_forum_counters($mergethread['fid'], $updated_stats);
1639              update_forum_lastpost($mergethread['fid']);
1640          }
1641          // Visibility changed
1642          elseif($mergethread['visible'] != $thread['visible'])
1643          {
1644              $updated_stats = array(
1645                  'posts' => 0,
1646                  'unapprovedposts' => 0,
1647                  'deletedposts' => 0
1648              );
1649  
1650              // If old thread is unapproved, implied counter comes in to effect
1651              if($mergethread['visible'] == 0)
1652              {
1653                  $updated_stats['unapprovedposts'] -= $mergethread['replies']+$mergethread['deletedposts'];
1654                  $updated_stats['posts'] += $mergethread['replies'];
1655                  $updated_stats['deletedposts'] += $mergethread['deletedposts'];
1656              }
1657              elseif($mergethread['visible'] == -1)
1658              {
1659                  $updated_stats['deletedposts'] -= $mergethread['replies']+$mergethread['unapprovedposts'];
1660                  $updated_stats['posts'] += $mergethread['replies'];
1661                  $updated_stats['unapprovedposts'] += $mergethread['unapprovedposts'];
1662              }
1663  
1664              // If new thread is unapproved, implied counter comes in to effect
1665              if($thread['visible'] == 0)
1666              {
1667                  $updated_stats['unapprovedposts'] += $mergethread['replies']+$mergethread['deletedposts'];
1668                  $updated_stats['posts'] -= $mergethread['replies'];
1669                  $updated_stats['deletedposts'] -= $mergethread['deletedposts'];
1670              }
1671              elseif($thread['visible'] == -1)
1672              {
1673                  $updated_stats['deletedposts'] += $mergethread['replies']+$mergethread['unapprovedposts'];
1674                  $updated_stats['posts'] -= $mergethread['replies'];
1675                  $updated_stats['unapprovedposts'] -= $mergethread['unapprovedposts'];
1676              }
1677  
1678              $new_stats = array();
1679              if($updated_stats['posts'] < 0)
1680              {
1681                  $new_stats['posts'] = $updated_stats['posts'];
1682              }
1683              elseif($updated_stats['posts'] > 0)
1684              {
1685                  $new_stats['posts'] = "+{$updated_stats['posts']}";
1686              }
1687  
1688              if($updated_stats['unapprovedposts'] < 0)
1689              {
1690                  $new_stats['unapprovedposts'] = $updated_stats['unapprovedposts'];
1691              }
1692              elseif($updated_stats['unapprovedposts'] > 0)
1693              {
1694                  $new_stats['unapprovedposts'] = "+{$updated_stats['unapprovedposts']}";
1695              }
1696  
1697              if($updated_stats['deletedposts'] < 0)
1698              {
1699                  $new_stats['deletedposts'] = $updated_stats['deletedposts'];
1700              }
1701              elseif($updated_stats['deletedposts'] > 0)
1702              {
1703                  $new_stats['deletedposts'] = "+{$updated_stats['deletedposts']}";
1704              }
1705  
1706              if(!empty($new_stats))
1707              {
1708                  update_forum_counters($mergethread['fid'], $new_stats);
1709                  update_forum_lastpost($mergethread['fid']);
1710              }
1711          }
1712  
1713          if($thread['visible'] != $new_firstpost['visible'])
1714          {
1715              // Correct counters
1716              if($new_firstpost['visible'] == 1)
1717              {
1718                  --$mergethread['replies'];
1719              }
1720              elseif($new_firstpost['visible'] == -1)
1721              {
1722                  --$mergethread['deletedposts'];
1723              }
1724              else
1725              {
1726                  --$mergethread['unapprovedposts'];
1727              }
1728              if($thread['visible'] == 1)
1729              {
1730                  ++$mergethread['replies'];
1731              }
1732              elseif($thread['visible'] == -1)
1733              {
1734                  ++$mergethread['deletedposts'];
1735              }
1736              else
1737              {
1738                  ++$mergethread['unapprovedposts'];
1739              }
1740          }
1741  
1742          // Update user counters
1743          foreach($user_posts as $uid => $counters)
1744          {
1745              $update_array = array(
1746                  "postnum" => "+{$counters['postnum']}",
1747                  "threadnum" => "+{$counters['threadnum']}",
1748              );
1749              update_user_counters($uid, $update_array);
1750          }
1751  
1752          $updated_stats = array(
1753              "replies" => "+{$mergethread['replies']}",
1754              "attachmentcount" => "+{$mergethread['attachmentcount']}",
1755              "unapprovedposts" => "+{$mergethread['unapprovedposts']}",
1756              "deletedposts" => "+{$mergethread['deletedposts']}"
1757          );
1758          update_thread_counters($tid, $updated_stats);
1759          update_last_post($tid);
1760  
1761          // Forum last post has to be updated after thread
1762          update_forum_lastpost($thread['fid']);
1763          return true;
1764      }
1765  
1766      /**
1767       * Split posts into a new/existing thread
1768       *
1769       * @param array $pids PIDs of posts to split
1770       * @param int $tid Original thread ID (this is only used as a base for the new
1771       * thread; it can be set to 0 when the posts specified are coming from more
1772       * than 1 thread)
1773       * @param int $moveto Destination forum
1774       * @param string $newsubject New thread subject
1775       * @param int $destination_tid TID if moving into existing thread
1776       * @return int|bool New thread ID or false on failure
1777       */
1778  	function split_posts($pids, $tid, $moveto, $newsubject, $destination_tid=0)
1779      {
1780          global $db, $thread, $plugins, $cache;
1781  
1782          $tid = (int)$tid;
1783          $moveto = (int)$moveto;
1784          $newtid = (int)$destination_tid;
1785  
1786          // Make sure we only have valid values
1787          $pids = array_map('intval', $pids);
1788  
1789          $pids_list = implode(',', $pids);
1790  
1791          // Get forum infos
1792          $forum_cache = $cache->read('forums');
1793  
1794          if(empty($pids) || !$forum_cache[$moveto])
1795          {
1796              return false;
1797          }
1798  
1799          // Get the first split post
1800          $query = $db->simple_select('posts', 'pid,uid,visible,icon,username,dateline', 'pid IN ('.$pids_list.')', array('order_by' => 'dateline, pid', 'limit' => 1));
1801  
1802          $post_info = $db->fetch_array($query);
1803  
1804          $visible = $post_info['visible'];
1805  
1806          $forum_counters[$moveto] = array(
1807              'threads' => 0,
1808              'deletedthreads' => 0,
1809              'unapprovedthreads' => 0,
1810              'posts' => 0,
1811              'unapprovedposts' => 0,
1812              'deletedposts' => 0
1813          );
1814  
1815          $user_counters = array();
1816  
1817          if($destination_tid == 0)
1818          {
1819              // Splitting into a new thread
1820              // Create the new thread
1821              $newsubject = $db->escape_string($newsubject);
1822              $newthread = array(
1823                  "fid" => $moveto,
1824                  "subject" => $newsubject,
1825                  "icon" => (int)$post_info['icon'],
1826                  "uid" => (int)$post_info['uid'],
1827                  "username" => $db->escape_string($post_info['username']),
1828                  "dateline" => (int)$post_info['dateline'],
1829                  "firstpost" => $post_info['pid'],
1830                  "lastpost" => 0,
1831                  "lastposter" => '',
1832                  "visible" => (int)$visible,
1833                  "notes" => ''
1834              );
1835              $newtid = $db->insert_query("threads", $newthread);
1836  
1837              if($visible == 1)
1838              {
1839                  ++$forum_counters[$moveto]['threads'];
1840                  if(!isset($user_counters[$newthread['uid']]))
1841                  {
1842                      $user_counters[$newthread['uid']] = array(
1843                          'postnum' => 0,
1844                          'threadnum' => 0
1845                      );
1846                  }
1847                  ++$user_counters[$newthread['uid']]['threadnum'];
1848              }
1849              elseif($visible == -1)
1850              {
1851                  ++$forum_counters[$moveto]['deletedthreads'];
1852              }
1853              else
1854              {
1855                  // Unapproved thread?
1856                  ++$forum_counters[$moveto]['unapprovedthreads'];
1857              }
1858          }
1859          else
1860          {
1861              $newthread = get_thread($newtid);
1862              if(!$newthread)
1863              {
1864                  return false;
1865              }
1866              $moveto = $newthread['fid'];
1867          }
1868  
1869          // Get selected posts before moving forums to keep old fid
1870          $original_posts_query = $db->query("
1871              SELECT p.pid, p.tid, p.fid, p.visible, p.uid, p.dateline, t.visible as threadvisible, t.firstpost, COUNT(a.aid) as postattachmentcount
1872              FROM ".TABLE_PREFIX."posts p
1873              LEFT JOIN ".TABLE_PREFIX."threads t ON (p.tid=t.tid)
1874              LEFT JOIN ".TABLE_PREFIX."attachments a ON (a.pid=p.pid AND a.visible=1)
1875              WHERE p.pid IN ($pids_list)
1876              GROUP BY p.pid
1877          ");
1878  
1879          // Move the selected posts over
1880          $sqlarray = array(
1881              "tid" => $newtid,
1882              "fid" => $moveto,
1883              "replyto" => 0
1884          );
1885          $db->update_query("posts", $sqlarray, "pid IN ($pids_list)");
1886  
1887          $thread_counters[$newtid] = array(
1888              'replies' => 0,
1889              'unapprovedposts' => 0,
1890              'deletedposts' => 0,
1891              'attachmentcount' => 0
1892          );
1893  
1894          // Get posts being merged
1895          while($post = $db->fetch_array($original_posts_query))
1896          {
1897              if(!isset($thread_counters[$post['tid']]))
1898              {
1899                  $thread_counters[$post['tid']] = array(
1900                      'replies' => 0,
1901                      'unapprovedposts' => 0,
1902                      'deletedposts' => 0,
1903                      'attachmentcount' => 0
1904                  );
1905              }
1906              if(!isset($forum_counters[$post['fid']]))
1907              {
1908                  $forum_counters[$post['fid']] = array(
1909                      'posts' => 0,
1910                      'unapprovedposts' => 0,
1911                      'deletedposts' => 0
1912                  );
1913              }
1914              if(!isset($user_counters[$post['uid']]))
1915              {
1916                  $user_counters[$post['uid']] = array(
1917                      'postnum' => 0,
1918                      'threadnum' => 0
1919                  );
1920              }
1921              if($post['visible'] == 1)
1922              {
1923                  // Modify users' post counts
1924                  if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usepostcounts'] == 1 && ($forum_cache[$moveto]['usepostcounts'] == 0 || $newthread['visible'] != 1))
1925                  {
1926                      // Moving into a forum that doesn't count post counts
1927                      --$user_counters[$post['uid']]['postnum'];
1928                  }
1929  
1930                  // Subtract 1 from the old thread's replies
1931                  --$thread_counters[$post['tid']]['replies'];
1932              }
1933              elseif($post['visible'] == 0)
1934              {
1935                  // Unapproved post
1936                  // Subtract 1 from the old thread's unapproved posts
1937                  --$thread_counters[$post['tid']]['unapprovedposts'];
1938              }
1939              elseif($post['visible'] == -1)
1940              {
1941                  // Soft deleted post
1942                  // Subtract 1 from the old thread's deleted posts
1943                  --$thread_counters[$post['tid']]['deletedposts'];
1944              }
1945  
1946              // Subtract 1 from the old forum's posts
1947              if($post['threadvisible'] == 1 && $post['visible'] == 1)
1948              {
1949                  --$forum_counters[$post['fid']]['posts'];
1950              }
1951              elseif($post['threadvisible'] == 0 || ($post['visible'] == 0 && $post['threadvisible'] == 1))
1952              {
1953                  --$forum_counters[$post['fid']]['unapprovedposts'];
1954              }
1955              else
1956              {
1957                  --$forum_counters[$post['fid']]['deletedposts'];
1958              }
1959  
1960              // Subtract attachment counts from old thread and add to new thread (which are counted regardless of post or attachment unapproval at time of coding)
1961              $thread_counters[$post['tid']]['attachmentcount'] -= $post['postattachmentcount'];
1962              $thread_counters[$newtid]['attachmentcount'] += $post['postattachmentcount'];
1963  
1964              if($post['firstpost'] == $post['pid'])
1965              {
1966                  // In some cases the first post of a thread changes
1967                  // Therefore resync the visible field to make sure they're the same if they're not
1968                  $query = $db->simple_select("posts", "pid, visible, uid", "tid='{$post['tid']}'", array('order_by' => 'dateline, pid', 'limit' => 1));
1969                  $new_firstpost = $db->fetch_array($query);
1970  
1971                  if(!isset($user_counters[$new_firstpost['uid']]))
1972                  {
1973                      $user_counters[$new_firstpost['uid']] = array(
1974                          'postnum' => 0,
1975                          'threadnum' => 0
1976                      );
1977                  }
1978  
1979                  // Update post counters if visibility changes
1980                  if($post['threadvisible'] != $new_firstpost['visible'])
1981                  {
1982                      $db->update_query("posts", array('visible' => $post['threadvisible']), "pid='{$new_firstpost['pid']}'");
1983                      // Subtract new first post
1984                      if($new_firstpost['visible'] == 1)
1985                      {
1986                          --$thread_counters[$post['tid']]['replies'];
1987                          if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usepostcounts'] == 1)
1988                          {
1989                              --$user_counters[$new_firstpost['uid']]['postnum'];
1990                          }
1991                      }
1992                      elseif($new_firstpost['visible'] == -1)
1993                      {
1994                          --$thread_counters[$post['tid']]['deletedposts'];
1995                      }
1996                      else
1997                      {
1998                          --$thread_counters[$post['tid']]['unapprovedposts'];
1999                      }
2000                      if($post['threadvisible'] == 0 || ($new_firstpost['visible'] == 0 && $post['threadvisible'] == 1))
2001                      {
2002                          --$forum_counters[$post['fid']]['unapprovedposts'];
2003                      }
2004                      else
2005                      {
2006                          --$forum_counters[$post['fid']]['deletedposts'];
2007                      }
2008  
2009                      // Add old first post
2010                      if($post['threadvisible'] == 1)
2011                      {
2012                          ++$thread_counters[$post['tid']]['replies'];
2013                          ++$forum_counters[$post['fid']]['posts'];
2014                          if($forum_cache[$post['fid']]['usepostcounts'] == 1)
2015                          {
2016                              ++$user_counters[$new_firstpost['uid']]['postnum'];
2017                          }
2018                      }
2019                      elseif($post['threadvisible'] == -1)
2020                      {
2021                          ++$thread_counters[$post['tid']]['deletedposts'];
2022                          ++$forum_counters[$post['fid']]['deletedposts'];
2023                      }
2024                      else
2025                      {
2026                          ++$thread_counters[$post['tid']]['unapprovedposts'];
2027                          ++$forum_counters[$post['fid']]['unapprovedposts'];
2028                      }
2029                  }
2030  
2031                  // Update user thread counter if thread opener changes
2032                  if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usethreadcounts'] == 1 && $post['uid'] != $new_firstpost['uid'])
2033                  {
2034                      // Subtract thread from old thread opener
2035                      --$user_counters[$post['uid']]['threadnum'];
2036                      // Add thread to new thread opener
2037                      ++$user_counters[$new_firstpost['uid']]['threadnum'];
2038                  }
2039                  update_first_post($post['tid']);
2040              }
2041  
2042              // This is the new first post of an existing thread?
2043              if($post['pid'] == $post_info['pid'] && $post['dateline'] < $newthread['dateline'])
2044              {
2045                  // Update post counters if visibility changes
2046                  if($post['visible'] != $newthread['visible'])
2047                  {
2048                      $db->update_query("posts", array('visible' => $newthread['visible']), "pid='{$post['pid']}'");
2049  
2050                      // This is needed to update the forum counters correctly
2051                      $post['visible'] = $newthread['visible'];
2052                  }
2053  
2054                  // Update user thread counter if thread opener changes
2055                  if($newthread['visible'] == 1 && $forum_cache[$newthread['fid']]['usethreadcounts'] == 1 && $post['uid'] != $newthread['uid'])
2056                  {
2057                      // Add thread to new thread opener
2058                      ++$user_counters[$post['uid']]['threadnum'];
2059                      if(!isset($user_counters[$newthread['uid']]))
2060                      {
2061                          $user_counters[$newthread['uid']] = array(
2062                              'postnum' => 0,
2063                              'threadnum' => 0
2064                          );
2065                      }
2066                      // Subtract thread from old thread opener
2067                      --$user_counters[$newthread['uid']]['threadnum'];
2068                  }
2069                  update_first_post($newtid);
2070              }
2071  
2072              if($post['visible'] == 1)
2073              {
2074                  // Modify users' post counts
2075                  if($newthread['visible'] == 1 && ($forum_cache[$post['fid']]['usepostcounts'] == 0 || $post['threadvisible'] != 1) && $forum_cache[$moveto]['usepostcounts'] == 1)
2076                  {
2077                      // Moving into a forum that does count post counts
2078                      ++$user_counters[$post['uid']]['postnum'];
2079                  }
2080  
2081                  // Add 1 to the new thread's replies
2082                  ++$thread_counters[$newtid]['replies'];
2083              }
2084              elseif($post['visible'] == 0)
2085              {
2086                  // Unapproved post
2087                  // Add 1 to the new thread's unapproved posts
2088                  ++$thread_counters[$newtid]['unapprovedposts'];
2089              }
2090              elseif($post['visible'] == -1)
2091              {
2092                  // Soft deleted post
2093                  // Add 1 to the new thread's deleted posts
2094                  ++$thread_counters[$newtid]['deletedposts'];
2095              }
2096  
2097              // Add 1 to the new forum's posts
2098              if($newthread['visible'] == 1 && $post['visible'] == 1)
2099              {
2100                  ++$forum_counters[$moveto]['posts'];
2101              }
2102              elseif($newthread['visible'] == 0 || ($post['visible'] == 0 && $newthread['visible'] == 1))
2103              {
2104                  ++$forum_counters[$moveto]['unapprovedposts'];
2105              }
2106              else
2107              {
2108                  ++$forum_counters[$moveto]['deletedposts'];
2109              }
2110          }
2111  
2112          if($destination_tid == 0 && $newthread['visible'] == 1)
2113          {
2114              // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post
2115              --$thread_counters[$newtid]['replies'];
2116          }
2117          elseif($destination_tid == 0 && $newthread['visible'] == 0)
2118          {
2119              // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post
2120              --$thread_counters[$newtid]['unapprovedposts'];
2121          }
2122          elseif($destination_tid == 0 && $newthread['visible'] == -1)
2123          {
2124              // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post
2125              --$thread_counters[$newtid]['deletedposts'];
2126          }
2127  
2128          $arguments = array("pids" => $pids, "tid" => $tid, "moveto" => $moveto, "newsubject" => $newsubject, "destination_tid" => $destination_tid);
2129          $plugins->run_hooks("class_moderation_split_posts", $arguments);
2130  
2131          // Update user post counts
2132          if(!empty($user_counters))
2133          {
2134              foreach($user_counters as $uid => $counters)
2135              {
2136                  foreach($counters as $key => $counter)
2137                  {
2138                      if($counter >= 0)
2139                      {
2140                          $counters[$key] = "+{$counter}"; // add the addition operator for query
2141                      }
2142                  }
2143                  update_user_counters($uid, $counters);
2144              }
2145          }
2146  
2147          // Update thread counters
2148          if(is_array($thread_counters))
2149          {
2150              foreach($thread_counters as $tid => $counters)
2151              {
2152                  if($tid == $newtid)
2153                  {
2154                      // Update the subject of the first post in the new thread
2155                      $query = $db->simple_select("posts", "pid", "tid='$newtid'", array('order_by' => 'dateline, pid', 'limit' => 1));
2156                      $newthread = $db->fetch_array($query);
2157                      $sqlarray = array(
2158                          "subject" => $newsubject,
2159                          "replyto" => 0
2160                      );
2161                      $db->update_query("posts", $sqlarray, "pid='{$newthread['pid']}'");
2162                  }
2163                  else
2164                  {
2165                      // Update the subject of the first post in the old thread
2166                      $query = $db->query("
2167                          SELECT p.pid, t.subject
2168                          FROM ".TABLE_PREFIX."posts p
2169                          LEFT JOIN ".TABLE_PREFIX."threads t ON (p.tid=t.tid)
2170                          WHERE p.tid='{$tid}'
2171                          ORDER BY p.dateline ASC, p.pid ASC
2172                          LIMIT 1
2173                      ");
2174                      $oldthread = $db->fetch_array($query);
2175                      $sqlarray = array(
2176                          "subject" => $db->escape_string($oldthread['subject']),
2177                          "replyto" => 0
2178                      );
2179                      $db->update_query("posts", $sqlarray, "pid='{$oldthread['pid']}'");
2180                  }
2181  
2182                  foreach($counters as $key => $counter)
2183                  {
2184                      if($counter >= 0)
2185                      {
2186                          $counters[$key] = "+{$counter}";
2187                      }
2188                  }
2189                  update_thread_counters($tid, $counters);
2190                  update_last_post($tid);
2191              }
2192          }
2193  
2194          // Update forum counters
2195          if(!empty($forum_counters))
2196          {
2197              foreach($forum_counters as $fid => $counters)
2198              {
2199                  foreach($counters as $key => $counter)
2200                  {
2201                      if($counter >= 0)
2202                      {
2203                          $counters[$key] = "+{$counter}";
2204                      }
2205                  }
2206                  update_forum_counters($fid, $counters);
2207                  update_forum_lastpost($fid);
2208              }
2209          }
2210  
2211          return $newtid;
2212      }
2213  
2214      /**
2215       * Move multiple threads to new forum
2216       *
2217       * @param array $tids Thread IDs
2218       * @param int $moveto Destination forum
2219       * @return boolean
2220       *
2221       * @deprecated Iterate over move_thread instead
2222       */
2223  	function move_threads($tids, $moveto)
2224      {
2225          global $db, $plugins;
2226  
2227          // Make sure we only have valid values
2228          $tids = array_map('intval', $tids);
2229  
2230          $tid_list = implode(',', $tids);
2231  
2232          $moveto = (int)$moveto;
2233  
2234          $newforum = get_forum($moveto);
2235  
2236          if(empty($tids) || !$newforum)
2237          {
2238              return false;
2239          }
2240  
2241          $total_posts = $total_unapproved_posts = $total_deleted_posts = $total_threads = $total_unapproved_threads = $total_deleted_threads = 0;
2242          $forum_counters = $user_counters = array();
2243          $query = $db->simple_select("threads", "fid, visible, replies, unapprovedposts, deletedposts, tid, uid", "tid IN ($tid_list)");
2244          while($thread = $db->fetch_array($query))
2245          {
2246              $forum = get_forum($thread['fid']);
2247  
2248              if(!isset($forum_counters[$thread['fid']]))
2249              {
2250                  $forum_counters[$thread['fid']] = array(
2251                      'posts' => 0,
2252                      'threads' => 0,
2253                      'unapprovedposts' => 0,
2254                      'unapprovedthreads' => 0,
2255                      'deletedthreads' => 0,
2256                      'deletedposts' => 0
2257                  );
2258              }
2259  
2260              if(!isset($user_counters[$thread['uid']]))
2261              {
2262                  $user_counters[$thread['uid']] = array(
2263                      'num_posts' => 0,
2264                      'num_threads' => 0
2265                  );
2266              }
2267  
2268              if($thread['visible'] == 1)
2269              {
2270                  $total_posts += $thread['replies']+1;
2271                  $total_unapproved_posts += $thread['unapprovedposts'];
2272                  $total_deleted_posts += $thread['deletedposts'];
2273                  $forum_counters[$thread['fid']]['posts'] += $thread['replies']+1;
2274                  $forum_counters[$thread['fid']]['unapprovedposts'] += $thread['unapprovedposts'];
2275                  $forum_counters[$thread['fid']]['deletedposts'] += $thread['deletedposts'];
2276  
2277                  $forum_counters[$thread['fid']]['threads']++;
2278                  ++$total_threads;
2279  
2280                  if($newforum['usethreadcounts'] == 1 && $forum['usethreadcounts'] == 0)
2281                  {
2282                      ++$user_counters[$thread['uid']]['num_threads'];
2283                  }
2284                  else if($newforum['usethreadcounts'] == 0 && $forum['usethreadcounts'] == 1)
2285                  {
2286                      --$user_counters[$thread['uid']]['num_threads'];
2287                  }
2288  
2289                  $query1 = $db->query("
2290                      SELECT COUNT(p.pid) AS posts, u.uid
2291                      FROM ".TABLE_PREFIX."posts p
2292                      LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid)
2293                      WHERE p.tid = '{$thread['tid']}' AND p.visible=1
2294                      GROUP BY u.uid
2295                      ORDER BY posts DESC
2296                  ");
2297                  while($posters = $db->fetch_array($query1))
2298                  {
2299                      if(!isset($user_counters[$posters['uid']]))
2300                      {
2301                          $user_counters[$posters['uid']] = array(
2302                              'num_posts' => 0,
2303                              'num_threads' => 0
2304                          );
2305                      }
2306  
2307                      if($newforum['usepostcounts'] != 0 && $forum['usepostcounts'] == 0)
2308                      {
2309                          $user_counters[$posters['uid']]['num_posts'] += $posters['posts'];
2310                      }
2311                      else if($newforum['usepostcounts'] == 0 && $forum['usepostcounts'] != 0)
2312                      {
2313                          $user_counters[$posters['uid']]['num_posts'] -= $posters['posts'];
2314                      }
2315                  }
2316              }
2317              elseif($thread['visible'] == -1)
2318              {
2319                  $total_deleted_posts += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1;
2320  
2321                  $forum_counters[$thread['fid']]['deletedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Implied deleted posts counter for deleted threads
2322  
2323                  $forum_counters[$thread['fid']]['deletedthreads']++;
2324                  ++$total_deleted_threads;
2325              }
2326              else
2327              {
2328                  $total_unapproved_posts += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1;
2329  
2330                  $forum_counters[$thread['fid']]['unapprovedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Implied unapproved posts counter for unapproved threads
2331  
2332                  $forum_counters[$thread['fid']]['unapprovedthreads']++;
2333                  ++$total_unapproved_threads;
2334              }
2335  
2336              // Remove old redirects
2337              $redirects_query = $db->simple_select('threads', 'tid', "closed='moved|{$thread['tid']}' AND fid='$moveto'");
2338              while($redirect_tid = $db->fetch_field($redirects_query, 'tid'))
2339              {
2340                  $this->delete_thread($redirect_tid);
2341              }
2342          }
2343  
2344          $sqlarray = array(
2345              "fid" => $moveto,
2346          );
2347          $db->update_query("threads", $sqlarray, "tid IN ($tid_list)");
2348          $db->update_query("posts", $sqlarray, "tid IN ($tid_list)");
2349  
2350          // If any of the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix
2351          $query = $db->simple_select("threads", "tid, prefix", "tid IN ($tid_list) AND prefix != 0");
2352          while($thread = $db->fetch_array($query))
2353          {
2354              switch($db->type)
2355              {
2356                  case "pgsql":
2357                  case "sqlite":
2358                      $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$moveto,%' OR forums='-1') AND pid='".$thread['prefix']."'");
2359                      break;
2360                  default:
2361                      $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$moveto,%' OR forums='-1') AND pid='".$thread['prefix']."'");
2362              }
2363              if($db->fetch_field($query, "num_prefixes") == 0)
2364              {
2365                  $sqlarray = array(
2366                      "prefix" => 0,
2367                  );
2368                  $db->update_query("threads", $sqlarray, "tid = '{$thread['tid']}'");
2369              }
2370          }
2371  
2372          $arguments = array("tids" => $tids, "moveto" => $moveto);
2373          $plugins->run_hooks("class_moderation_move_threads", $arguments);
2374  
2375          if(!empty($user_counters))
2376          {
2377              foreach($user_counters as $uid => $counters)
2378              {
2379                  $update_array = array(
2380                      "postnum" => "+{$counters['num_posts']}",
2381                      "threadnum" => "+{$counters['num_threads']}",
2382                  );
2383                  update_user_counters($uid, $update_array);
2384              }
2385          }
2386  
2387          if(is_array($forum_counters))
2388          {
2389              foreach($forum_counters as $fid => $counter)
2390              {
2391                  $updated_count = array(
2392                      'posts' => "-{$counter['posts']}",
2393                      'threads' => "-{$counter['threads']}",
2394                      'unapprovedposts' => "-{$counter['unapprovedposts']}",
2395                      'unapprovedthreads' => "-{$counter['unapprovedthreads']}",
2396                      'deletedposts' => "-{$counter['deletedposts']}",
2397                      'deletedthreads' => "-{$counter['deletedthreads']}"
2398  
2399                  );
2400                  update_forum_counters($fid, $updated_count);
2401                  update_forum_lastpost($fid);
2402              }
2403          }
2404  
2405          $updated_count = array(
2406              "threads" => "+{$total_threads}",
2407              "unapprovedthreads" => "+{$total_unapproved_threads}",
2408              "posts" => "+{$total_posts}",
2409              "unapprovedposts" => "+{$total_unapproved_posts}",
2410              'deletedposts' => "+{$total_deleted_posts}",
2411              "deletedthreads" => "+{$total_deleted_threads}"
2412          );
2413  
2414          update_forum_counters($moveto, $updated_count);
2415          update_forum_lastpost($moveto);
2416  
2417          // Remove thread subscriptions for the users who no longer have permission to view the thread
2418          $this->remove_thread_subscriptions($tid_list, false, $moveto);
2419  
2420          return true;
2421      }
2422  
2423      /**
2424       * Approve multiple posts
2425       *
2426       * @param array $pids PIDs
2427       * @return boolean
2428       */
2429  	function approve_posts($pids)
2430      {
2431          global $db, $cache, $plugins;
2432  
2433          $num_posts = 0;
2434  
2435          if(empty($pids))
2436          {
2437              return false;
2438          }
2439  
2440          // Make sure we only have valid values
2441          $pids = array_map('intval', $pids);
2442  
2443          $pid_list = implode(',', $pids);
2444          $pids = $threads_to_update = array();
2445  
2446          // Make visible
2447          $approve = array(
2448              "visible" => 1,
2449          );
2450  
2451          // We have three cases we deal with in these code segments:
2452          // 1) We're approving specific unapproved posts
2453          // 1.1) if the thread is approved
2454          // 1.2) if the thread is unapproved
2455          // 2) We're approving the firstpost of the thread, therefore approving the thread itself
2456          // 3) We're doing both 1 and 2
2457          $query = $db->query("
2458              SELECT p.tid
2459              FROM ".TABLE_PREFIX."posts p
2460              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
2461              WHERE p.pid IN ($pid_list) AND p.visible = '0' AND t.firstpost = p.pid AND t.visible = 0
2462          ");
2463          while($post = $db->fetch_array($query))
2464          {
2465              // This is the first post in the thread so we're approving the whole thread.
2466              $threads_to_update[] = $post['tid'];
2467          }
2468  
2469          if(!empty($threads_to_update))
2470          {
2471              $this->approve_threads($threads_to_update);
2472          }
2473  
2474          $thread_counters = $forum_counters = $user_counters = array();
2475  
2476          $query = $db->query("
2477              SELECT p.pid, p.tid, p.fid, p.uid, t.visible AS threadvisible
2478              FROM ".TABLE_PREFIX."posts p
2479              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
2480              WHERE p.pid IN ($pid_list) AND p.visible = '0' AND t.firstpost != p.pid
2481          ");
2482          while($post = $db->fetch_array($query))
2483          {
2484              $pids[] = $post['pid'];
2485  
2486              if(!isset($thread_counters[$post['tid']]))
2487              {
2488                  $thread_counters[$post['tid']] = array(
2489                      'replies' => 0
2490                  );
2491              }
2492  
2493              ++$thread_counters[$post['tid']]['replies'];
2494  
2495              // If the thread of this post is unapproved then we've already taken into account this counter as implied.
2496              // Updating it again would cause it to double count
2497              if($post['threadvisible'] == 1)
2498              {
2499                  if(!isset($forum_counters[$post['fid']]))
2500                  {
2501                      $forum_counters[$post['fid']] = array(
2502                          'num_posts' => 0
2503                      );
2504                  }
2505                  ++$forum_counters[$post['fid']]['num_posts'];
2506              }
2507  
2508              $forum = get_forum($post['fid']);
2509  
2510              // If post counts enabled in this forum and the thread is approved, add 1
2511              if($forum['usepostcounts'] != 0 && $post['threadvisible'] == 1)
2512              {
2513                  if(!isset($user_counters[$post['uid']]))
2514                  {
2515                      $user_counters[$post['uid']] = 0;
2516                  }
2517                  ++$user_counters[$post['uid']];
2518              }
2519          }
2520  
2521          if(empty($pids) && empty($threads_to_update))
2522          {
2523              return false;
2524          }
2525  
2526          if(!empty($pids))
2527          {
2528              $where = "pid IN (".implode(',', $pids).")";
2529              $db->update_query("posts", $approve, $where);
2530          }
2531  
2532          $plugins->run_hooks("class_moderation_approve_posts", $pids);
2533  
2534          if(!empty($thread_counters))
2535          {
2536              foreach($thread_counters as $tid => $counters)
2537              {
2538                  $counters_update = array(
2539                      "unapprovedposts" => "-".$counters['replies'],
2540                      "replies" => "+".$counters['replies']
2541                  );
2542                  update_thread_counters($tid, $counters_update);
2543                  update_last_post($tid);
2544              }
2545          }
2546  
2547          if(!empty($forum_counters))
2548          {
2549              foreach($forum_counters as $fid => $counters)
2550              {
2551                  $updated_forum_stats = array(
2552                      'posts' => "+{$counters['num_posts']}",
2553                      'unapprovedposts' => "-{$counters['num_posts']}",
2554                  );
2555                  update_forum_counters($fid, $updated_forum_stats);
2556                  update_forum_lastpost($fid);
2557              }
2558          }
2559  
2560          if(!empty($user_counters))
2561          {
2562              foreach($user_counters as $uid => $counter)
2563              {
2564                  update_user_counters($uid, array('postnum' => "+{$counter}"));
2565              }
2566          }
2567  
2568          return true;
2569      }
2570  
2571      /**
2572       * Unapprove multiple posts
2573       *
2574       * @param array $pids PIDs
2575       * @return boolean
2576       */
2577  	function unapprove_posts($pids)
2578      {
2579          global $db, $cache, $plugins;
2580  
2581          if(empty($pids))
2582          {
2583              return false;
2584          }
2585  
2586          // Make sure we only have valid values
2587          $pids = array_map('intval', $pids);
2588  
2589          $pid_list = implode(',', $pids);
2590          $pids = $threads_to_update = array();
2591  
2592          // Make invisible
2593          $approve = array(
2594              "visible" => 0,
2595          );
2596  
2597          // We have three cases we deal with in these code segments:
2598          // 1) We're unapproving specific approved posts
2599          // 1.1) if the thread is approved
2600          // 1.2) if the thread is unapproved
2601          // 1.3) if the thread is deleted
2602          // 2) We're unapproving the firstpost of the thread, therefore unapproving the thread itself
2603          // 3) We're doing both 1 and 2
2604          $query = $db->query("
2605              SELECT p.tid
2606              FROM ".TABLE_PREFIX."posts p
2607              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
2608              WHERE p.pid IN ($pid_list) AND p.visible IN (-1,1) AND t.firstpost = p.pid AND t.visible IN (-1,1)
2609          ");
2610          while($post = $db->fetch_array($query))
2611          {
2612              // This is the first post in the thread so we're unapproving the whole thread.
2613              $threads_to_update[] = $post['tid'];
2614          }
2615  
2616          if(!empty($threads_to_update))
2617          {
2618              $this->unapprove_threads($threads_to_update);
2619          }
2620  
2621          $thread_counters = $forum_counters = $user_counters = array();
2622  
2623          $query = $db->query("
2624              SELECT p.pid, p.tid, p.visible, p.fid, p.uid, t.visible AS threadvisible
2625              FROM ".TABLE_PREFIX."posts p
2626              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
2627              WHERE p.pid IN ($pid_list) AND p.visible IN (-1,1) AND t.firstpost != p.pid
2628          ");
2629          while($post = $db->fetch_array($query))
2630          {
2631              $pids[] = $post['pid'];
2632  
2633              if(!isset($thread_counters[$post['tid']]))
2634              {
2635                  $thread_counters[$post['tid']] = array(
2636                      'replies' => 0,
2637                      'unapprovedposts' => 0,
2638                      'deletedposts' => 0
2639                  );
2640              }
2641  
2642              ++$thread_counters[$post['tid']]['unapprovedposts'];
2643              if($post['visible'] == 1)
2644              {
2645                  ++$thread_counters[$post['tid']]['replies'];
2646              }
2647              else
2648              {
2649                  ++$thread_counters[$post['tid']]['deletedposts'];
2650              }
2651  
2652              if(!isset($forum_counters[$post['fid']]))
2653              {
2654                  $forum_counters[$post['fid']] = array(
2655                      'num_posts' => 0,
2656                      'num_unapproved_posts' => 0,
2657                      'num_deleted_posts' => 0
2658                  );
2659              }
2660  
2661              // If the thread of this post is unapproved then we've already taken into account this counter as implied.
2662              // Updating it again would cause it to double count
2663              if($post['threadvisible'] != 0)
2664              {
2665                  ++$forum_counters[$post['fid']]['num_unapproved_posts'];
2666                  if($post['visible'] == 1)
2667                  {
2668                      ++$forum_counters[$post['fid']]['num_posts'];
2669                  }
2670                  else
2671                  {
2672                      ++$forum_counters[$post['fid']]['num_deleted_posts'];
2673                  }
2674              }
2675  
2676              $forum = get_forum($post['fid']);
2677  
2678              // If post counts enabled in this forum and the thread is approved, subtract 1
2679              if($forum['usepostcounts'] != 0 && $post['visible'] == 1 && $post['threadvisible'] == 1)
2680              {
2681                  if(!isset($user_counters[$post['uid']]))
2682                  {
2683                      $user_counters[$post['uid']] = 0;
2684                  }
2685                  --$user_counters[$post['uid']];
2686              }
2687          }
2688  
2689          if(empty($pids) && empty($threads_to_update))
2690          {
2691              return false;
2692          }
2693  
2694          if(!empty($pids))
2695          {
2696              $where = "pid IN (".implode(',', $pids).")";
2697              $db->update_query("posts", $approve, $where);
2698          }
2699  
2700          $plugins->run_hooks("class_moderation_unapprove_posts", $pids);
2701  
2702          if(!empty($thread_counters))
2703          {
2704              foreach($thread_counters as $tid => $counters)
2705              {
2706                  $counters_update = array(
2707                      "unapprovedposts" => "+".$counters['unapprovedposts'],
2708                      "replies" => "-".$counters['replies'],
2709                      "deletedposts" => "-".$counters['deletedposts']
2710                  );
2711  
2712                  update_thread_counters($tid, $counters_update);
2713                  update_last_post($tid);
2714              }
2715          }
2716  
2717          if(!empty($forum_counters))
2718          {
2719              foreach($forum_counters as $fid => $counters)
2720              {
2721                  $updated_forum_stats = array(
2722                      'posts' => "-{$counters['num_posts']}",
2723                      'unapprovedposts' => "+{$counters['num_unapproved_posts']}",
2724                      'deletedposts' => "-{$counters['num_deleted_posts']}"
2725                  );
2726                  update_forum_counters($fid, $updated_forum_stats);
2727                  update_forum_lastpost($fid);
2728              }
2729          }
2730  
2731          if(!empty($user_counters))
2732          {
2733              foreach($user_counters as $uid => $counter)
2734              {
2735                  update_user_counters($uid, array('postnum' => "{$counter}"));
2736              }
2737          }
2738  
2739          return true;
2740      }
2741  
2742      /**
2743       * Change thread subject
2744       *
2745       * @param int|array $tids Thread ID(s)
2746       * @param string $format Format of new subject (with {subject})
2747       * @return boolean
2748       */
2749  	function change_thread_subject($tids, $format)
2750      {
2751          global $db, $mybb, $plugins;
2752  
2753          // Get tids into list
2754          if(!is_array($tids))
2755          {
2756              $tids = array($tids);
2757          }
2758  
2759          // Make sure we only have valid values
2760          $tids = array_map('intval', $tids);
2761  
2762          if(empty($tids))
2763          {
2764              return false;
2765          }
2766  
2767          $tid_list = implode(',', $tids);
2768  
2769          // Get original subject
2770          $query = $db->query("
2771              SELECT u.uid, u.username, t.tid, t.subject FROM ".TABLE_PREFIX."threads t
2772              LEFT JOIN ".TABLE_PREFIX."users u ON t.uid=u.uid
2773              WHERE tid IN ($tid_list)
2774          ");
2775          while($thread = $db->fetch_array($query))
2776          {
2777              // Update threads and first posts with new subject
2778              $find = array('{username}', 'author', '{subject}');
2779              $replace = array($mybb->user['username'], $thread['username'], $thread['subject']);
2780  
2781              $new_subject = str_ireplace($find, $replace, $format);
2782  
2783              $args = array(
2784                  'thread' => &$thread,
2785                  'new_subject' => &$new_subject,
2786              );
2787  
2788              $plugins->run_hooks("class_moderation_change_thread_subject_newsubject", $args);
2789  
2790              $update_subject = array(
2791                  "subject" => $db->escape_string($new_subject)
2792              );
2793              $db->update_query("threads", $update_subject, "tid='{$thread['tid']}'");
2794              $db->update_query("posts", $update_subject, "tid='{$thread['tid']}' AND replyto='0'");
2795          }
2796  
2797          $arguments = array("tids" => $tids, "format" => $format);
2798          $plugins->run_hooks("class_moderation_change_thread_subject", $arguments);
2799  
2800          return true;
2801      }
2802  
2803      /**
2804       * Add thread expiry
2805       *
2806       * @param int $tid Thread ID
2807       * @param int $deletetime Timestamp when the thread is deleted
2808       * @return boolean
2809       */
2810  	function expire_thread($tid, $deletetime)
2811      {
2812          global $db, $plugins;
2813  
2814          $tid = (int)$tid;
2815  
2816          if(empty($tid))
2817          {
2818              return false;
2819          }
2820  
2821          $update_thread = array(
2822              "deletetime" => (int)$deletetime
2823          );
2824          $db->update_query("threads", $update_thread, "tid='{$tid}'");
2825  
2826          $arguments = array("tid" => $tid, "deletetime" => $deletetime);
2827          $plugins->run_hooks("class_moderation_expire_thread", $arguments);
2828  
2829          return true;
2830      }
2831  
2832      /**
2833       * Toggle post visibility (approved/unapproved)
2834       *
2835       * @param array $pids Post IDs
2836       * @return boolean true
2837       */
2838  	function toggle_post_visibility($pids)
2839      {
2840          global $db;
2841  
2842          // Make sure we only have valid values
2843          $pids = array_map('intval', $pids);
2844  
2845          $pid_list = implode(',', $pids);
2846          $query = $db->simple_select("posts", 'pid, visible', "pid IN ($pid_list)");
2847          while($post = $db->fetch_array($query))
2848          {
2849              if($post['visible'] != 0)
2850              {
2851                  $unapprove[] = $post['pid'];
2852              }
2853              else
2854              {
2855                  $approve[] = $post['pid'];
2856              }
2857          }
2858          if(is_array($unapprove))
2859          {
2860              $this->unapprove_posts($unapprove);
2861          }
2862          if(is_array($approve))
2863          {
2864              $this->approve_posts($approve);
2865          }
2866          return true;
2867      }
2868  
2869      /**
2870       * Toggle post visibility (deleted/restored)
2871       *
2872       * @param array $pids Post IDs
2873       * @return boolean true
2874       */
2875  	function toggle_post_softdelete($pids)
2876      {
2877          global $db;
2878  
2879          // Make sure we only have valid values
2880          $pids = array_map('intval', $pids);
2881  
2882          $pid_list = implode(',', $pids);
2883          $query = $db->simple_select("posts", 'pid, visible', "pid IN ($pid_list)");
2884          while($post = $db->fetch_array($query))
2885          {
2886              if($post['visible'] != -1)
2887              {
2888                  $delete[] = $post['pid'];
2889              }
2890              else
2891              {
2892                  $restore[] = $post['pid'];
2893              }
2894          }
2895          if(is_array($delete))
2896          {
2897              $this->soft_delete_posts($delete);
2898          }
2899          if(is_array($restore))
2900          {
2901              $this->restore_posts($restore);
2902          }
2903          return true;
2904      }
2905  
2906      /**
2907       * Toggle thread visibility (approved/unapproved)
2908       *
2909       * @param array $tids Thread IDs
2910       * @param int $fid Forum ID
2911       * @return boolean true
2912       */
2913  	function toggle_thread_visibility($tids, $fid)
2914      {
2915          global $db;
2916  
2917          // Make sure we only have valid values
2918          $tids = array_map('intval', $tids);
2919          $fid = (int)$fid;
2920  
2921          $tid_list = implode(',', $tids);
2922          $query = $db->simple_select("threads", 'tid, visible', "tid IN ($tid_list)");
2923          while($thread = $db->fetch_array($query))
2924          {
2925              if($thread['visible'] != 0)
2926              {
2927                  $unapprove[] = $thread['tid'];
2928              }
2929              else
2930              {
2931                  $approve[] = $thread['tid'];
2932              }
2933          }
2934          if(is_array($unapprove))
2935          {
2936              $this->unapprove_threads($unapprove, $fid);
2937          }
2938          if(is_array($approve))
2939          {
2940              $this->approve_threads($approve, $fid);
2941          }
2942          return true;
2943      }
2944  
2945      /**
2946       * Toggle thread visibility (deleted/restored)
2947       *
2948       * @param array $tids Thread IDs
2949       * @return boolean true
2950       */
2951  	function toggle_thread_softdelete($tids)
2952      {
2953          global $db;
2954  
2955          // Make sure we only have valid values
2956          $tids = array_map('intval', $tids);
2957  
2958          $tid_list = implode(',', $tids);
2959          $query = $db->simple_select("threads", 'tid, visible', "tid IN ($tid_list)");
2960          while($thread = $db->fetch_array($query))
2961          {
2962              if($thread['visible'] != -1)
2963              {
2964                  $delete[] = $thread['tid'];
2965              }
2966              else
2967              {
2968                  $restore[] = $thread['tid'];
2969              }
2970          }
2971          if(is_array($delete))
2972          {
2973              $this->soft_delete_threads($delete);
2974          }
2975          if(is_array($restore))
2976          {
2977              $this->restore_threads($restore);
2978          }
2979          return true;
2980      }
2981  
2982      /**
2983       * Toggle threads open/closed
2984       *
2985       * @param array $tids Thread IDs
2986       * @return boolean true
2987       */
2988  	function toggle_thread_status($tids)
2989      {
2990          global $db;
2991  
2992          // Make sure we only have valid values
2993          $tids = array_map('intval', $tids);
2994  
2995          $tid_list = implode(',', $tids);
2996          $query = $db->simple_select("threads", 'tid, closed', "tid IN ($tid_list)");
2997          while($thread = $db->fetch_array($query))
2998          {
2999              if($thread['closed'] == 1)
3000              {
3001                  $open[] = $thread['tid'];
3002              }
3003              elseif($thread['closed'] == 0)
3004              {
3005                  $close[] = $thread['tid'];
3006              }
3007          }
3008          if(is_array($open))
3009          {
3010              $this->open_threads($open);
3011          }
3012          if(is_array($close))
3013          {
3014              $this->close_threads($close);
3015          }
3016          return true;
3017      }
3018  
3019      /**
3020       * Toggle threads stick/unstick
3021       *
3022       * @param array $tids Thread IDs
3023       * @return boolean true
3024       */
3025  	function toggle_thread_importance($tids)
3026      {
3027          global $db;
3028  
3029          // Make sure we only have valid values
3030          $tids = array_map('intval', $tids);
3031  
3032          $stick = array();
3033          $unstick = array();
3034  
3035          $tid_list = implode(',', $tids);
3036          $query = $db->simple_select("threads", 'tid, sticky', "tid IN ($tid_list)");
3037          while($thread = $db->fetch_array($query))
3038          {
3039              if($thread['sticky'] == 0)
3040              {
3041                  $stick[] = $thread['tid'];
3042              }
3043              elseif($thread['sticky'] == 1)
3044              {
3045                  $unstick[] = $thread['tid'];
3046              }
3047          }
3048          if(!empty($stick))
3049          {
3050              $this->stick_threads($stick);
3051          }
3052          if(!empty($unstick))
3053          {
3054              $this->unstick_threads($unstick);
3055          }
3056          return true;
3057      }
3058  
3059      /**
3060       * Remove thread subscriptions (from one or multiple threads in the same forum)
3061       *
3062       * @param int|array $tids Thread ID, or an array of thread IDs from the same forum.
3063       * @param boolean $all True (default) to delete all subscriptions, false to only delete subscriptions from users with no permission to read the thread
3064       * @param int $fid (Only applies if $all is false) The forum ID of the thread
3065       * @return boolean
3066       */
3067  	function remove_thread_subscriptions($tids, $all = true, $fid = 0)
3068      {
3069          global $db, $plugins;
3070  
3071          // Format thread IDs
3072          if(!is_array($tids))
3073          {
3074              $tids = array($tids);
3075          }
3076  
3077          if(empty($tids))
3078          {
3079              return false;
3080          }
3081  
3082          // Make sure we only have valid values
3083          $tids = array_map('intval', $tids);
3084          $fid = (int)$fid;
3085  
3086          $tids_csv = implode(',', $tids);
3087  
3088          // Delete only subscriptions from users who no longer have permission to read the thread.
3089          if(!$all)
3090          {
3091              // Get groups that cannot view the forum or its threads
3092              $forum_parentlist = get_parent_list($fid);
3093              $query = $db->simple_select("forumpermissions", "gid", "fid IN ({$forum_parentlist}) AND (canview=0 OR canviewthreads=0)");
3094              $groups = array();
3095              $additional_groups = '';
3096              while($group = $db->fetch_array($query))
3097              {
3098                  $groups[] = $group['gid'];
3099                  switch($db->type)
3100                  {
3101                      case "pgsql":
3102                      case "sqlite":
3103                          $additional_groups .= " OR ','||u.additionalgroups||',' LIKE ',{$group['gid']},'";
3104                          break;
3105                      default:
3106                          $additional_groups .= " OR CONCAT(',',u.additionalgroups,',') LIKE ',{$group['gid']},'";
3107                  }
3108              }
3109              // If there are groups found, delete subscriptions from users in these groups
3110              if(count($groups) > 0)
3111              {
3112                  $groups_csv = implode(',', $groups);
3113                  $query = $db->query("
3114                      SELECT s.tid, u.uid
3115                      FROM ".TABLE_PREFIX."threadsubscriptions s
3116                      LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=s.uid)
3117                      WHERE s.tid IN ({$tids_csv})
3118                      AND (u.usergroup IN ({$groups_csv}){$additional_groups})
3119                  ");
3120                  while($subscription = $db->fetch_array($query))
3121                  {
3122                      $db->delete_query("threadsubscriptions", "uid='{$subscription['uid']}' AND tid='{$subscription['tid']}'");
3123                  }
3124              }
3125          }
3126          // Delete all subscriptions of this thread
3127          else
3128          {
3129              $db->delete_query("threadsubscriptions", "tid IN ({$tids_csv})");
3130          }
3131  
3132          $arguments = array("tids" => $tids, "all" => $all, "fid" => $fid);
3133          $plugins->run_hooks("class_moderation_remove_thread_subscriptions", $arguments);
3134  
3135          return true;
3136      }
3137  
3138      /**
3139       * Apply a thread prefix (to one or multiple threads in the same forum)
3140       *
3141       * @param int|array $tids Thread ID, or an array of thread IDs from the same forum.
3142       * @param int $prefix Prefix ID to apply to the threads
3143       * @return bool
3144       */
3145  	function apply_thread_prefix($tids, $prefix = 0)
3146      {
3147          global $db, $plugins;
3148  
3149          // Format thread IDs
3150          if(!is_array($tids))
3151          {
3152              $tids = array($tids);
3153          }
3154  
3155          if(empty($tids))
3156          {
3157              return false;
3158          }
3159  
3160          // Make sure we only have valid values
3161          $tids = array_map('intval', $tids);
3162          $tids_csv = implode(',', $tids);
3163  
3164          $update_thread = array('prefix' => (int)$prefix);
3165          $db->update_query('threads', $update_thread, "tid IN ({$tids_csv})");
3166  
3167          $arguments = array('tids' => $tids, 'prefix' => $prefix);
3168  
3169          $plugins->run_hooks('class_moderation_apply_thread_prefix', $arguments);
3170  
3171          return true;
3172      }
3173  
3174      /**
3175       * Soft delete multiple posts
3176       *
3177       * @param array $pids PIDs
3178       * @return boolean
3179       */
3180  	function soft_delete_posts($pids)
3181      {
3182          global $db, $cache, $plugins;
3183  
3184          if(empty($pids))
3185          {
3186              return false;
3187          }
3188  
3189          // Make sure we only have valid values
3190          $pids = array_map('intval', $pids);
3191  
3192          $pid_list = implode(',', $pids);
3193          $pids = $threads_to_update = array();
3194  
3195          // Make invisible
3196          $update = array(
3197              "visible" => -1,
3198          );
3199  
3200          // We have three cases we deal with in these code segments:
3201          // 1) We're deleting specific approved posts
3202          // 1.1) if the thread is approved
3203          // 1.2) if the thread is unapproved
3204          // 1.3) if the thread is deleted
3205          // 2) We're deleting the firstpost of the thread, therefore deleting the thread itself
3206          // 3) We're doing both 1 and 2
3207          $query = $db->query("
3208              SELECT p.tid
3209              FROM ".TABLE_PREFIX."posts p
3210              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
3211              WHERE p.pid IN ($pid_list) AND p.visible IN (0,1) AND t.firstpost = p.pid AND t.visible IN (0,1)
3212          ");
3213          while($post = $db->fetch_array($query))
3214          {
3215              // This is the first post in the thread so we're deleting the whole thread.
3216              $threads_to_update[] = $post['tid'];
3217          }
3218  
3219          if(!empty($threads_to_update))
3220          {
3221              $this->soft_delete_threads($threads_to_update);
3222          }
3223  
3224          $thread_counters = $forum_counters = $user_counters = array();
3225  
3226          $query = $db->query("
3227              SELECT p.pid, p.tid, p.visible, f.fid, f.usepostcounts, p.uid, t.visible AS threadvisible
3228              FROM ".TABLE_PREFIX."posts p
3229              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
3230              LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid)
3231              WHERE p.pid IN ($pid_list) AND p.visible IN (0,1) AND t.firstpost != p.pid
3232          ");
3233          while($post = $db->fetch_array($query))
3234          {
3235              $pids[] = $post['pid'];
3236  
3237              if(!isset($thread_counters[$post['tid']]))
3238              {
3239                  $thread_counters[$post['tid']] = array(
3240                      'replies' => 0,
3241                      'unapprovedposts' => 0,
3242                      'deletedposts' => 0
3243                  );
3244              }
3245  
3246              ++$thread_counters[$post['tid']]['deletedposts'];
3247              if($post['visible'] == 1)
3248              {
3249                  ++$thread_counters[$post['tid']]['replies'];
3250              }
3251              else
3252              {
3253                  ++$thread_counters[$post['tid']]['unapprovedposts'];
3254              }
3255  
3256              if(!isset($forum_counters[$post['fid']]))
3257              {
3258                  $forum_counters[$post['fid']] = array(
3259                      'num_posts' => 0,
3260                      'num_unapproved_posts' => 0,
3261                      'num_deleted_posts' => 0
3262                  );
3263              }
3264  
3265              // If the thread of this post is deleted then we've already taken into account this counter as implied.
3266              // Updating it again would cause it to double count
3267              if($post['threadvisible'] == 1)
3268              {
3269                  ++$forum_counters[$post['fid']]['num_deleted_posts'];
3270                  if($post['visible'] == 1)
3271                  {
3272                      ++$forum_counters[$post['fid']]['num_posts'];
3273                  }
3274                  else
3275                  {
3276                      ++$forum_counters[$post['fid']]['num_unapproved_posts'];
3277                  }
3278              }
3279  
3280              // If post counts enabled in this forum and the thread is approved, subtract 1
3281              if($post['usepostcounts'] != 0 && $post['threadvisible'] == 1 && $post['visible'] == 1)
3282              {
3283                  if(!isset($user_counters[$post['uid']]))
3284                  {
3285                      $user_counters[$post['uid']] = 0;
3286                  }
3287                  --$user_counters[$post['uid']];
3288              }
3289          }
3290  
3291          if(empty($pids) && empty($threads_to_update))
3292          {
3293              return false;
3294          }
3295  
3296          if(!empty($pids))
3297          {
3298              $where = "pid IN (".implode(',', $pids).")";
3299              $db->update_query("posts", $update, $where);
3300              mark_reports($pids, "posts");
3301          }
3302  
3303          $plugins->run_hooks("class_moderation_soft_delete_posts", $pids);
3304  
3305          if(is_array($thread_counters))
3306          {
3307              foreach($thread_counters as $tid => $counters)
3308              {
3309                  $counters_update = array(
3310                      "unapprovedposts" => "-".$counters['unapprovedposts'],
3311                      "replies" => "-".$counters['replies'],
3312                      "deletedposts" => "+".$counters['deletedposts']
3313                  );
3314  
3315                  update_thread_counters($tid, $counters_update);
3316                  update_last_post($tid);
3317              }
3318          }
3319  
3320          if(is_array($forum_counters))
3321          {
3322              foreach($forum_counters as $fid => $counters)
3323              {
3324                  $updated_forum_stats = array(
3325                      'posts' => "-{$counters['num_posts']}",
3326                      'unapprovedposts' => "-{$counters['num_unapproved_posts']}",
3327                      'deletedposts' => "+{$counters['num_deleted_posts']}"
3328                  );
3329                  update_forum_counters($fid, $updated_forum_stats);
3330                  update_forum_lastpost($fid);
3331              }
3332          }
3333  
3334          if(!empty($user_counters))
3335          {
3336              foreach($user_counters as $uid => $counter)
3337              {
3338                  update_user_counters($uid, array('postnum' => "{$counter}"));
3339              }
3340          }
3341  
3342          return true;
3343      }
3344  
3345      /**
3346       * Restore multiple posts
3347       *
3348       * @param array $pids PIDs
3349       * @return boolean
3350       */
3351  	function restore_posts($pids)
3352      {
3353          global $db, $cache, $plugins;
3354  
3355          $num_posts = 0;
3356  
3357          if(empty($pids))
3358          {
3359              return false;
3360          }
3361  
3362          // Make sure we only have valid values
3363          $pids = array_map('intval', $pids);
3364  
3365          $pid_list = implode(',', $pids);
3366          $pids = $threads_to_update = array();
3367  
3368          // Make visible
3369          $update = array(
3370              "visible" => 1,
3371          );
3372  
3373          // We have three cases we deal with in these code segments:
3374          // 1) We're approving specific restored posts
3375          // 1.1) if the thread is deleted
3376          // 1.2) if the thread is restored
3377          // 2) We're restoring the firstpost of the thread, therefore restoring the thread itself
3378          // 3) We're doing both 1 and 2
3379          $query = $db->query("
3380              SELECT p.tid
3381              FROM ".TABLE_PREFIX."posts p
3382              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
3383              WHERE p.pid IN ($pid_list) AND p.visible = '-1' AND t.firstpost = p.pid AND t.visible = -1
3384          ");
3385          while($post = $db->fetch_array($query))
3386          {
3387              // This is the first post in the thread so we're approving the whole thread.
3388              $threads_to_update[] = $post['tid'];
3389          }
3390  
3391          if(!empty($threads_to_update))
3392          {
3393              $this->restore_threads($threads_to_update);
3394          }
3395  
3396          $thread_counters = $forum_counters = $user_counters = array();
3397  
3398          $query = $db->query("
3399              SELECT p.pid, p.tid, f.fid, f.usepostcounts, p.uid, t.visible AS threadvisible
3400              FROM ".TABLE_PREFIX."posts p
3401              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
3402              LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid)
3403              WHERE p.pid IN ($pid_list) AND p.visible = '-1' AND t.firstpost != p.pid
3404          ");
3405          while($post = $db->fetch_array($query))
3406          {
3407              $pids[] = $post['pid'];
3408  
3409              if(!isset($thread_counters[$post['tid']]))
3410              {
3411                  $thread_counters[$post['tid']] = array(
3412                      'replies' => 0
3413                  );
3414              }
3415  
3416              ++$thread_counters[$post['tid']]['replies'];
3417  
3418              // If the thread of this post is deleted then we've already taken into account this counter as implied.
3419              // Updating it again would cause it to double count
3420              if($post['threadvisible'] == 1)
3421              {
3422                  if(!isset($forum_counters[$post['fid']]))
3423                  {
3424                      $forum_counters[$post['fid']] = array(
3425                          'num_posts' => 0
3426                      );
3427                  }
3428                  ++$forum_counters[$post['fid']]['num_posts'];
3429              }
3430  
3431              // If post counts enabled in this forum and the thread is approved, add 1
3432              if($post['usepostcounts'] != 0 && $post['threadvisible'] == 1)
3433              {
3434                  if(!isset($user_counters[$post['uid']]))
3435                  {
3436                      $user_counters[$post['uid']] = 0;
3437                  }
3438                  ++$user_counters[$post['uid']];
3439  
3440              }
3441          }
3442  
3443          if(empty($pids) && empty($threads_to_update))
3444          {
3445              return false;
3446          }
3447  
3448          if(!empty($pids))
3449          {
3450              $where = "pid IN (".implode(',', $pids).")";
3451              $db->update_query("posts", $update, $where);
3452          }
3453  
3454          $plugins->run_hooks("class_moderation_restore_posts", $pids);
3455  
3456          if(is_array($thread_counters))
3457          {
3458              foreach($thread_counters as $tid => $counters)
3459              {
3460                  $counters_update = array(
3461                      "deletedposts" => "-".$counters['replies'],
3462                      "replies" => "+".$counters['replies']
3463                  );
3464                  update_thread_counters($tid, $counters_update);
3465                  update_last_post($tid);
3466              }
3467          }
3468  
3469          if(is_array($forum_counters))
3470          {
3471              foreach($forum_counters as $fid => $counters)
3472              {
3473                  $updated_forum_stats = array(
3474                      'posts' => "+{$counters['num_posts']}",
3475                      'deletedposts' => "-{$counters['num_posts']}"
3476                  );
3477                  update_forum_counters($fid, $updated_forum_stats);
3478                  update_forum_lastpost($fid);
3479              }
3480          }
3481  
3482          if(!empty($user_counters))
3483          {
3484              foreach($user_counters as $uid => $counter)
3485              {
3486                  update_user_counters($uid, array('postnum' => "+{$counter}"));
3487              }
3488          }
3489  
3490          return true;
3491      }
3492  
3493      /**
3494       * Restore one or more threads
3495       *
3496       * @param array|int $tids Thread ID(s)
3497       * @return boolean true
3498       */
3499  	function restore_threads($tids)
3500      {
3501          global $db, $cache, $plugins;
3502  
3503          if(!is_array($tids))
3504          {
3505              $tids = array($tids);
3506          }
3507  
3508          if(empty($tids))
3509          {
3510              return false;
3511          }
3512  
3513          // Make sure we only have valid values
3514          $tids = array_map('intval', $tids);
3515  
3516          $tid_list = $forum_counters = $user_counters = $posts_to_restore = array();
3517  
3518          $tids_list = implode(",", $tids);
3519          $query = $db->simple_select("threads", "*", "tid IN ($tids_list)");
3520  
3521          while($thread = $db->fetch_array($query))
3522          {
3523              if($thread['visible'] != -1)
3524              {
3525                  continue;
3526              }
3527              $tid_list[] = $thread['tid'];
3528  
3529              $forum = get_forum($thread['fid']);
3530  
3531              if(!isset($forum_counters[$forum['fid']]))
3532              {
3533                  $forum_counters[$forum['fid']] = array(
3534                      'num_posts' => 0,
3535                      'num_threads' => 0,
3536                      'num_deleted_posts' => 0,
3537                      'num_unapproved_posts' => 0
3538                  );
3539              }
3540  
3541              if(!isset($user_counters[$thread['uid']]))
3542              {
3543                  $user_counters[$thread['uid']] = array(
3544                      'num_posts' => 0,
3545                      'num_threads' => 0
3546                  );
3547              }
3548  
3549              ++$forum_counters[$forum['fid']]['num_threads'];
3550              $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Remove implied visible from count
3551              $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['replies']+$thread['unapprovedposts']+1;
3552              $forum_counters[$forum['fid']]['num_unapproved_posts'] += $thread['unapprovedposts'];
3553  
3554              if($forum['usepostcounts'] != 0)
3555              {
3556                  // On approving thread restore user post counts
3557                  $query = $db->simple_select("posts", "COUNT(pid) as posts, uid", "tid='{$thread['tid']}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid");
3558                  while($counter = $db->fetch_array($query))
3559                  {
3560                      if(!isset($user_counters[$counter['uid']]['num_posts']))
3561                      {
3562                          $user_counters[$counter['uid']]['num_posts'] = 0;
3563                      }
3564                      $user_counters[$counter['uid']]['num_posts'] += $counter['posts'];
3565                  }
3566              }
3567  
3568              if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|')
3569              {
3570                  ++$user_counters[$thread['uid']]['num_threads'];
3571              }
3572  
3573              $posts_to_restore[] = $thread['firstpost'];
3574          }
3575  
3576          if(!empty($tid_list))
3577          {
3578              $tid_moved_list = "";
3579              $comma = "";
3580              foreach($tid_list as $tid)
3581              {
3582                  $tid_moved_list .= "{$comma}'moved|{$tid}'";
3583                  $comma = ",";
3584              }
3585              $tid_list = implode(',', $tid_list);
3586              $update = array(
3587                  "visible" => 1
3588              );
3589              $db->update_query("threads", $update, "tid IN ($tid_list)");
3590              // Restore redirects, too
3591              $redirect_tids = array();
3592              $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})");
3593              while($redirect_tid = $db->fetch_field($query, 'tid'))
3594              {
3595                  $redirect_tids[] = $redirect_tid;
3596              }
3597              if(!empty($redirect_tids))
3598              {
3599                  $this->restore_threads($redirect_tids);
3600              }
3601              if(!empty($posts_to_restore))
3602              {
3603                  $db->update_query("posts", $update, "pid IN (".implode(',', $posts_to_restore).")");
3604              }
3605  
3606              $plugins->run_hooks("class_moderation_restore_threads", $tids);
3607  
3608              if(is_array($forum_counters))
3609              {
3610                  foreach($forum_counters as $fid => $counters)
3611                  {
3612                      // Update stats
3613                      $update_array = array(
3614                          "threads" => "+{$counters['num_threads']}",
3615                          "posts" => "+{$counters['num_posts']}",
3616                          "unapprovedposts" => "+{$counters['num_unapproved_posts']}",
3617                          "deletedposts" => "-{$counters['num_deleted_posts']}",
3618                          "deletedthreads" => "-{$counters['num_threads']}"
3619                      );
3620                      update_forum_counters($fid, $update_array);
3621                      update_forum_lastpost($fid);
3622                  }
3623              }
3624  
3625              if(!empty($user_counters))
3626              {
3627                  foreach($user_counters as $uid => $counters)
3628                  {
3629                      $update_array = array(
3630                          "postnum" => "+{$counters['num_posts']}",
3631                          "threadnum" => "+{$counters['num_threads']}",
3632                      );
3633                      update_user_counters($uid, $update_array);
3634                  }
3635              }
3636          }
3637          return true;
3638      }
3639  
3640      /**
3641       * Soft delete one or more threads
3642       *
3643       * @param array|int Thread ID(s)
3644       * @return boolean
3645       */
3646  	function soft_delete_threads($tids)
3647      {
3648          global $db, $cache, $plugins;
3649  
3650          if(!is_array($tids))
3651          {
3652              $tids = array($tids);
3653          }
3654  
3655          if(empty($tids))
3656          {
3657              return false;
3658          }
3659  
3660          // Make sure we only have valid values
3661          $tids = array_map('intval', $tids);
3662  
3663          $tid_list = implode(',', $tids);
3664          $tid_moved_list = "";
3665          $comma = "";
3666          foreach($tids as $tid)
3667          {
3668              $tid_moved_list .= "{$comma}'moved|{$tid}'";
3669              $comma = ",";
3670          }
3671  
3672          $forum_counters = $user_counters = $posts_to_delete = array();
3673  
3674          $tids_list = implode(",", $tids);
3675          $query = $db->simple_select("threads", "*", "tid IN ($tids_list)");
3676  
3677          while($thread = $db->fetch_array($query))
3678          {
3679              $forum = get_forum($thread['fid']);
3680  
3681              if($thread['visible'] == 1 || $thread['visible'] == 0)
3682              {
3683                  if(!isset($forum_counters[$forum['fid']]))
3684                  {
3685                      $forum_counters[$forum['fid']] = array(
3686                          'num_posts' => 0,
3687                          'num_threads' => 0,
3688                          'num_deleted_threads' => 0,
3689                          'num_deleted_posts' => 0,
3690                          'unapproved_threads' => 0,
3691                          'unapproved_posts' => 0
3692                      );
3693                  }
3694  
3695                  if(!isset($user_counters[$thread['uid']]))
3696                  {
3697                      $user_counters[$thread['uid']] = array(
3698                          'num_posts' => 0,
3699                          'num_threads' => 0
3700                      );
3701                  }
3702  
3703                  ++$forum_counters[$forum['fid']]['num_deleted_threads'];
3704                  $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['replies']+$thread['unapprovedposts']+1;
3705  
3706                  if($thread['visible'] == 1)
3707                  {
3708                      ++$forum_counters[$forum['fid']]['num_threads'];
3709                      $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Add implied invisible to count
3710                      $forum_counters[$forum['fid']]['unapproved_posts'] += $thread['unapprovedposts'];
3711                  }
3712                  else
3713                  {
3714                      ++$forum_counters[$forum['fid']]['unapproved_threads'];
3715                      $forum_counters[$forum['fid']]['unapproved_posts'] += $thread['replies']+$thread['deletedposts']+$thread['unapprovedposts']+1; // Add implied invisible to count
3716                      $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['deletedposts'];
3717                  }
3718  
3719                  // On unapproving thread update user post counts
3720                  if($thread['visible'] == 1 && $forum['usepostcounts'] != 0)
3721                  {
3722                      $query = $db->simple_select("posts", "COUNT(pid) AS posts, uid", "tid='{$thread['tid']}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid");
3723                      while($counter = $db->fetch_array($query))
3724                      {
3725                          if(!isset($user_counters[$counter['uid']]['num_posts']))
3726                          {
3727                              $user_counters[$counter['uid']]['num_posts'] = 0;
3728                          }
3729                          $user_counters[$counter['uid']]['num_posts'] += $counter['posts'];
3730                      }
3731                  }
3732  
3733                  if($thread['visible'] == 1 && $forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|')
3734                  {
3735                      ++$user_counters[$thread['uid']]['num_threads'];
3736                  }
3737              }
3738              $posts_to_delete[] = $thread['firstpost'];
3739          }
3740  
3741          $update = array(
3742              "visible" => -1
3743          );
3744          $db->update_query("threads", $update, "tid IN ($tid_list)");
3745          // Soft delete redirects, too
3746          $redirect_tids = array();
3747          $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})");
3748  
3749          mark_reports($tids, "threads");
3750  
3751          while($redirect_tid = $db->fetch_field($query, 'tid'))
3752          {
3753              $redirect_tids[] = $redirect_tid;
3754          }
3755          if(!empty($redirect_tids))
3756          {
3757              $this->soft_delete_threads($redirect_tids);
3758          }
3759          if(!empty($posts_to_delete))
3760          {
3761              $db->update_query("posts", $update, "pid IN (".implode(',', $posts_to_delete).")");
3762          }
3763  
3764          $plugins->run_hooks("class_moderation_soft_delete_threads", $tids);
3765  
3766          if(is_array($forum_counters))
3767          {
3768              foreach($forum_counters as $fid => $counters)
3769              {
3770                  // Update stats
3771                  $update_array = array(
3772                      "threads" => "-{$counters['num_threads']}",
3773                      "unapprovedthreads" => "-{$counters['unapproved_threads']}",
3774                      "posts" => "-{$counters['num_posts']}",
3775                      "unapprovedposts" => "-{$counters['unapproved_posts']}",
3776                      "deletedposts" => "+{$counters['num_deleted_posts']}",
3777                      "deletedthreads" => "+{$counters['num_deleted_threads']}"
3778                  );
3779                  update_forum_counters($fid, $update_array);
3780                  update_forum_lastpost($fid);
3781              }
3782          }
3783  
3784          if(!empty($user_counters))
3785          {
3786              foreach($user_counters as $uid => $counters)
3787              {
3788                  $update_array = array(
3789                      "postnum" => "-{$counters['num_posts']}",
3790                      "threadnum" => "-{$counters['num_threads']}",
3791                  );
3792                  update_user_counters($uid, $update_array);
3793              }
3794          }
3795  
3796          return true;
3797      }
3798  }


2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup Cross-referenced by PHPXref