[ Index ]

PHP Cross Reference of MyBB 1.8.37

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


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