[ Index ]

PHP Cross Reference of MyBB 1.8.38

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          // Attach moved posts to the first post
1599          $db->update_query("posts", array('replyto' => $new_firstpost['pid']), "tid='{$tid}' AND replyto = 0 AND pid != '{$new_firstpost['pid']}'");
1600  
1601          // Update thread count if thread has a new firstpost and is visible
1602          if($thread['uid'] != $new_firstpost['uid'] && $thread['visible'] == 1 && $forum_cache[$thread['fid']]['usethreadcounts'] == 1)
1603          {
1604              if(!isset($user_posts[$thread['uid']]['threadnum']))
1605              {
1606                  $user_posts[$thread['uid']]['threadnum'] = 0;
1607              }
1608              --$user_posts[$thread['uid']]['threadnum'];
1609              if(!isset($user_posts[$new_firstpost['uid']]['threadnum']))
1610              {
1611                  $user_posts[$new_firstpost['uid']]['threadnum'] = 0;
1612              }
1613              ++$user_posts[$new_firstpost['uid']]['threadnum'];
1614          }
1615  
1616          // Thread is not in current forum
1617          if($mergethread['fid'] != $thread['fid'])
1618          {
1619              // If new thread is unapproved, implied counter comes in to effect
1620              if($thread['visible'] == 0)
1621              {
1622                  $updated_stats = array(
1623                      "unapprovedposts" => '+'.($mergethread['replies']+$mergethread['unapprovedposts']+$mergethread['deletedposts'])
1624                  );
1625              }
1626              elseif($thread['visible'] == -1)
1627              {
1628                  $updated_stats = array(
1629                      "deletedposts" => '+'.($mergethread['replies']+$mergethread['deletedposts']+$mergethread['unapprovedposts'])
1630                  );
1631              }
1632              else
1633              {
1634                  $updated_stats = array(
1635                      "posts" => "+{$mergethread['replies']}",
1636                      "unapprovedposts" => "+{$mergethread['unapprovedposts']}",
1637                      "deletedposts" => "+{$mergethread['deletedposts']}"
1638                  );
1639              }
1640              update_forum_counters($thread['fid'], $updated_stats);
1641  
1642              // If old thread is unapproved, implied counter comes in to effect
1643              if($mergethread['visible'] == 0)
1644              {
1645                  $updated_stats = array(
1646                      "unapprovedposts" => '-'.($mergethread['replies']+$mergethread['unapprovedposts']+$mergethread['deletedposts'])
1647                  );
1648              }
1649              elseif($mergethread['visible'] == -1)
1650              {
1651                  $updated_stats = array(
1652                      "deletedposts" => '-'.($mergethread['replies']+$mergethread['deletedposts']+$mergethread['unapprovedposts'])
1653                  );
1654              }
1655              else
1656              {
1657                  $updated_stats = array(
1658                      "posts" => "-{$mergethread['replies']}",
1659                      "unapprovedposts" => "-{$mergethread['unapprovedposts']}",
1660                      "deletedposts" => "-{$mergethread['deletedposts']}"
1661                  );
1662              }
1663              update_forum_counters($mergethread['fid'], $updated_stats);
1664              update_forum_lastpost($mergethread['fid']);
1665          }
1666          // Visibility changed
1667          elseif($mergethread['visible'] != $thread['visible'])
1668          {
1669              $updated_stats = array(
1670                  'posts' => 0,
1671                  'unapprovedposts' => 0,
1672                  'deletedposts' => 0
1673              );
1674  
1675              // If old thread is unapproved, implied counter comes in to effect
1676              if($mergethread['visible'] == 0)
1677              {
1678                  $updated_stats['unapprovedposts'] -= $mergethread['replies']+$mergethread['deletedposts'];
1679                  $updated_stats['posts'] += $mergethread['replies'];
1680                  $updated_stats['deletedposts'] += $mergethread['deletedposts'];
1681              }
1682              elseif($mergethread['visible'] == -1)
1683              {
1684                  $updated_stats['deletedposts'] -= $mergethread['replies']+$mergethread['unapprovedposts'];
1685                  $updated_stats['posts'] += $mergethread['replies'];
1686                  $updated_stats['unapprovedposts'] += $mergethread['unapprovedposts'];
1687              }
1688  
1689              // If new thread is unapproved, implied counter comes in to effect
1690              if($thread['visible'] == 0)
1691              {
1692                  $updated_stats['unapprovedposts'] += $mergethread['replies']+$mergethread['deletedposts'];
1693                  $updated_stats['posts'] -= $mergethread['replies'];
1694                  $updated_stats['deletedposts'] -= $mergethread['deletedposts'];
1695              }
1696              elseif($thread['visible'] == -1)
1697              {
1698                  $updated_stats['deletedposts'] += $mergethread['replies']+$mergethread['unapprovedposts'];
1699                  $updated_stats['posts'] -= $mergethread['replies'];
1700                  $updated_stats['unapprovedposts'] -= $mergethread['unapprovedposts'];
1701              }
1702  
1703              $new_stats = array();
1704              if($updated_stats['posts'] < 0)
1705              {
1706                  $new_stats['posts'] = $updated_stats['posts'];
1707              }
1708              elseif($updated_stats['posts'] > 0)
1709              {
1710                  $new_stats['posts'] = "+{$updated_stats['posts']}";
1711              }
1712  
1713              if($updated_stats['unapprovedposts'] < 0)
1714              {
1715                  $new_stats['unapprovedposts'] = $updated_stats['unapprovedposts'];
1716              }
1717              elseif($updated_stats['unapprovedposts'] > 0)
1718              {
1719                  $new_stats['unapprovedposts'] = "+{$updated_stats['unapprovedposts']}";
1720              }
1721  
1722              if($updated_stats['deletedposts'] < 0)
1723              {
1724                  $new_stats['deletedposts'] = $updated_stats['deletedposts'];
1725              }
1726              elseif($updated_stats['deletedposts'] > 0)
1727              {
1728                  $new_stats['deletedposts'] = "+{$updated_stats['deletedposts']}";
1729              }
1730  
1731              if(!empty($new_stats))
1732              {
1733                  update_forum_counters($mergethread['fid'], $new_stats);
1734                  update_forum_lastpost($mergethread['fid']);
1735              }
1736          }
1737  
1738          if($thread['visible'] != $new_firstpost['visible'])
1739          {
1740              // Correct counters
1741              if($new_firstpost['visible'] == 1)
1742              {
1743                  --$mergethread['replies'];
1744              }
1745              elseif($new_firstpost['visible'] == -1)
1746              {
1747                  --$mergethread['deletedposts'];
1748              }
1749              else
1750              {
1751                  --$mergethread['unapprovedposts'];
1752              }
1753              if($thread['visible'] == 1)
1754              {
1755                  ++$mergethread['replies'];
1756              }
1757              elseif($thread['visible'] == -1)
1758              {
1759                  ++$mergethread['deletedposts'];
1760              }
1761              else
1762              {
1763                  ++$mergethread['unapprovedposts'];
1764              }
1765          }
1766  
1767          // Update user counters
1768          foreach($user_posts as $uid => $counters)
1769          {
1770              $update_array = array(
1771                  "postnum" => "+{$counters['postnum']}",
1772                  "threadnum" => "+{$counters['threadnum']}",
1773              );
1774              update_user_counters($uid, $update_array);
1775          }
1776  
1777          $updated_stats = array(
1778              "replies" => "+{$mergethread['replies']}",
1779              "attachmentcount" => "+{$mergethread['attachmentcount']}",
1780              "unapprovedposts" => "+{$mergethread['unapprovedposts']}",
1781              "deletedposts" => "+{$mergethread['deletedposts']}"
1782          );
1783          update_thread_counters($tid, $updated_stats);
1784          update_last_post($tid);
1785  
1786          // Forum last post has to be updated after thread
1787          update_forum_lastpost($thread['fid']);
1788          return true;
1789      }
1790  
1791      /**
1792       * Split posts into a new/existing thread
1793       *
1794       * @param array $pids PIDs of posts to split
1795       * @param int $tid Original thread ID (this is only used as a base for the new
1796       * thread; it can be set to 0 when the posts specified are coming from more
1797       * than 1 thread)
1798       * @param int $moveto Destination forum
1799       * @param string $newsubject New thread subject
1800       * @param int $destination_tid TID if moving into existing thread
1801       * @return int|bool New thread ID or false on failure
1802       */
1803  	function split_posts($pids, $tid, $moveto, $newsubject, $destination_tid=0)
1804      {
1805          global $db, $thread, $plugins, $cache;
1806  
1807          $tid = (int)$tid;
1808          $moveto = (int)$moveto;
1809          $newtid = (int)$destination_tid;
1810  
1811          // Make sure we only have valid values
1812          $pids = array_map('intval', $pids);
1813  
1814          $pids_list = implode(',', $pids);
1815  
1816          // Get forum infos
1817          $forum_cache = $cache->read('forums');
1818  
1819          if(empty($pids) || !$forum_cache[$moveto])
1820          {
1821              return false;
1822          }
1823  
1824          // Get the first split post
1825          $query = $db->simple_select('posts', 'pid,uid,visible,icon,username,dateline', 'pid IN ('.$pids_list.')', array('order_by' => 'dateline, pid', 'limit' => 1));
1826  
1827          $post_info = $db->fetch_array($query);
1828  
1829          $visible = $post_info['visible'];
1830  
1831          $forum_counters[$moveto] = array(
1832              'threads' => 0,
1833              'deletedthreads' => 0,
1834              'unapprovedthreads' => 0,
1835              'posts' => 0,
1836              'unapprovedposts' => 0,
1837              'deletedposts' => 0
1838          );
1839  
1840          $user_counters = array();
1841  
1842          if($destination_tid == 0)
1843          {
1844              // Splitting into a new thread
1845              // Create the new thread
1846              $newsubject = $db->escape_string($newsubject);
1847              $newthread = array(
1848                  "fid" => $moveto,
1849                  "subject" => $newsubject,
1850                  "icon" => (int)$post_info['icon'],
1851                  "uid" => (int)$post_info['uid'],
1852                  "username" => $db->escape_string($post_info['username']),
1853                  "dateline" => (int)$post_info['dateline'],
1854                  "firstpost" => $post_info['pid'],
1855                  "lastpost" => 0,
1856                  "lastposter" => '',
1857                  "visible" => (int)$visible,
1858                  "notes" => ''
1859              );
1860              $newtid = $db->insert_query("threads", $newthread);
1861  
1862              if($visible == 1)
1863              {
1864                  ++$forum_counters[$moveto]['threads'];
1865                  if(!isset($user_counters[$newthread['uid']]))
1866                  {
1867                      $user_counters[$newthread['uid']] = array(
1868                          'postnum' => 0,
1869                          'threadnum' => 0
1870                      );
1871                  }
1872                  ++$user_counters[$newthread['uid']]['threadnum'];
1873              }
1874              elseif($visible == -1)
1875              {
1876                  ++$forum_counters[$moveto]['deletedthreads'];
1877              }
1878              else
1879              {
1880                  // Unapproved thread?
1881                  ++$forum_counters[$moveto]['unapprovedthreads'];
1882              }
1883          }
1884          else
1885          {
1886              $newthread = get_thread($newtid);
1887              if(!$newthread)
1888              {
1889                  return false;
1890              }
1891              $moveto = $newthread['fid'];
1892          }
1893  
1894          // Get selected posts before moving forums to keep old fid
1895          $original_posts_query = $db->query("
1896              SELECT p.pid, p.tid, p.fid, p.visible, p.uid, p.dateline, t.visible as threadvisible, t.firstpost, COUNT(a.aid) as postattachmentcount
1897              FROM ".TABLE_PREFIX."posts p
1898              LEFT JOIN ".TABLE_PREFIX."threads t ON (p.tid=t.tid)
1899              LEFT JOIN ".TABLE_PREFIX."attachments a ON (a.pid=p.pid AND a.visible=1)
1900              WHERE p.pid IN ($pids_list)
1901              GROUP BY p.pid
1902          ");
1903  
1904          // Move the selected posts over
1905          $sqlarray = array(
1906              "tid" => $newtid,
1907              "fid" => $moveto,
1908              "replyto" => 0
1909          );
1910          $db->update_query("posts", $sqlarray, "pid IN ($pids_list)");
1911  
1912          $thread_counters[$newtid] = array(
1913              'replies' => 0,
1914              'unapprovedposts' => 0,
1915              'deletedposts' => 0,
1916              'attachmentcount' => 0
1917          );
1918  
1919          // Get posts being merged
1920          while($post = $db->fetch_array($original_posts_query))
1921          {
1922              if(!isset($thread_counters[$post['tid']]))
1923              {
1924                  $thread_counters[$post['tid']] = array(
1925                      'replies' => 0,
1926                      'unapprovedposts' => 0,
1927                      'deletedposts' => 0,
1928                      'attachmentcount' => 0
1929                  );
1930              }
1931              if(!isset($forum_counters[$post['fid']]))
1932              {
1933                  $forum_counters[$post['fid']] = array(
1934                      'posts' => 0,
1935                      'unapprovedposts' => 0,
1936                      'deletedposts' => 0
1937                  );
1938              }
1939              if(!isset($user_counters[$post['uid']]))
1940              {
1941                  $user_counters[$post['uid']] = array(
1942                      'postnum' => 0,
1943                      'threadnum' => 0
1944                  );
1945              }
1946              if($post['visible'] == 1)
1947              {
1948                  // Modify users' post counts
1949                  if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usepostcounts'] == 1 && ($forum_cache[$moveto]['usepostcounts'] == 0 || $newthread['visible'] != 1))
1950                  {
1951                      // Moving into a forum that doesn't count post counts
1952                      --$user_counters[$post['uid']]['postnum'];
1953                  }
1954  
1955                  // Subtract 1 from the old thread's replies
1956                  --$thread_counters[$post['tid']]['replies'];
1957              }
1958              elseif($post['visible'] == 0)
1959              {
1960                  // Unapproved post
1961                  // Subtract 1 from the old thread's unapproved posts
1962                  --$thread_counters[$post['tid']]['unapprovedposts'];
1963              }
1964              elseif($post['visible'] == -1)
1965              {
1966                  // Soft deleted post
1967                  // Subtract 1 from the old thread's deleted posts
1968                  --$thread_counters[$post['tid']]['deletedposts'];
1969              }
1970  
1971              // Subtract 1 from the old forum's posts
1972              if($post['threadvisible'] == 1 && $post['visible'] == 1)
1973              {
1974                  --$forum_counters[$post['fid']]['posts'];
1975              }
1976              elseif($post['threadvisible'] == 0 || ($post['visible'] == 0 && $post['threadvisible'] == 1))
1977              {
1978                  --$forum_counters[$post['fid']]['unapprovedposts'];
1979              }
1980              else
1981              {
1982                  --$forum_counters[$post['fid']]['deletedposts'];
1983              }
1984  
1985              // Subtract attachment counts from old thread and add to new thread (which are counted regardless of post or attachment unapproval at time of coding)
1986              $thread_counters[$post['tid']]['attachmentcount'] -= $post['postattachmentcount'];
1987              $thread_counters[$newtid]['attachmentcount'] += $post['postattachmentcount'];
1988  
1989              if($post['firstpost'] == $post['pid'])
1990              {
1991                  // In some cases the first post of a thread changes
1992                  // Therefore resync the visible field to make sure they're the same if they're not
1993                  $query = $db->simple_select("posts", "pid, visible, uid", "tid='{$post['tid']}'", array('order_by' => 'dateline, pid', 'limit' => 1));
1994                  $new_firstpost = $db->fetch_array($query);
1995  
1996                  if(!isset($user_counters[$new_firstpost['uid']]))
1997                  {
1998                      $user_counters[$new_firstpost['uid']] = array(
1999                          'postnum' => 0,
2000                          'threadnum' => 0
2001                      );
2002                  }
2003  
2004                  // Update post counters if visibility changes
2005                  if($post['threadvisible'] != $new_firstpost['visible'])
2006                  {
2007                      $db->update_query("posts", array('visible' => $post['threadvisible']), "pid='{$new_firstpost['pid']}'");
2008                      // Subtract new first post
2009                      if($new_firstpost['visible'] == 1)
2010                      {
2011                          --$thread_counters[$post['tid']]['replies'];
2012                          if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usepostcounts'] == 1)
2013                          {
2014                              --$user_counters[$new_firstpost['uid']]['postnum'];
2015                          }
2016                      }
2017                      elseif($new_firstpost['visible'] == -1)
2018                      {
2019                          --$thread_counters[$post['tid']]['deletedposts'];
2020                      }
2021                      else
2022                      {
2023                          --$thread_counters[$post['tid']]['unapprovedposts'];
2024                      }
2025                      if($post['threadvisible'] == 0 || ($new_firstpost['visible'] == 0 && $post['threadvisible'] == 1))
2026                      {
2027                          --$forum_counters[$post['fid']]['unapprovedposts'];
2028                      }
2029                      else
2030                      {
2031                          --$forum_counters[$post['fid']]['deletedposts'];
2032                      }
2033  
2034                      // Add old first post
2035                      if($post['threadvisible'] == 1)
2036                      {
2037                          ++$thread_counters[$post['tid']]['replies'];
2038                          ++$forum_counters[$post['fid']]['posts'];
2039                          if($forum_cache[$post['fid']]['usepostcounts'] == 1)
2040                          {
2041                              ++$user_counters[$new_firstpost['uid']]['postnum'];
2042                          }
2043                      }
2044                      elseif($post['threadvisible'] == -1)
2045                      {
2046                          ++$thread_counters[$post['tid']]['deletedposts'];
2047                          ++$forum_counters[$post['fid']]['deletedposts'];
2048                      }
2049                      else
2050                      {
2051                          ++$thread_counters[$post['tid']]['unapprovedposts'];
2052                          ++$forum_counters[$post['fid']]['unapprovedposts'];
2053                      }
2054                  }
2055  
2056                  // Update user thread counter if thread opener changes
2057                  if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usethreadcounts'] == 1 && $post['uid'] != $new_firstpost['uid'])
2058                  {
2059                      // Subtract thread from old thread opener
2060                      --$user_counters[$post['uid']]['threadnum'];
2061                      // Add thread to new thread opener
2062                      ++$user_counters[$new_firstpost['uid']]['threadnum'];
2063                  }
2064                  update_first_post($post['tid']);
2065              }
2066  
2067              // This is the new first post of an existing thread?
2068              if($post['pid'] == $post_info['pid'] && $post['dateline'] < $newthread['dateline'])
2069              {
2070                  // Update post counters if visibility changes
2071                  if($post['visible'] != $newthread['visible'])
2072                  {
2073                      $db->update_query("posts", array('visible' => $newthread['visible']), "pid='{$post['pid']}'");
2074  
2075                      // This is needed to update the forum counters correctly
2076                      $post['visible'] = $newthread['visible'];
2077                  }
2078  
2079                  // Update user thread counter if thread opener changes
2080                  if($newthread['visible'] == 1 && $forum_cache[$newthread['fid']]['usethreadcounts'] == 1 && $post['uid'] != $newthread['uid'])
2081                  {
2082                      // Add thread to new thread opener
2083                      ++$user_counters[$post['uid']]['threadnum'];
2084                      if(!isset($user_counters[$newthread['uid']]))
2085                      {
2086                          $user_counters[$newthread['uid']] = array(
2087                              'postnum' => 0,
2088                              'threadnum' => 0
2089                          );
2090                      }
2091                      // Subtract thread from old thread opener
2092                      --$user_counters[$newthread['uid']]['threadnum'];
2093                  }
2094                  update_first_post($newtid);
2095              }
2096  
2097              if($post['visible'] == 1)
2098              {
2099                  // Modify users' post counts
2100                  if($newthread['visible'] == 1 && ($forum_cache[$post['fid']]['usepostcounts'] == 0 || $post['threadvisible'] != 1) && $forum_cache[$moveto]['usepostcounts'] == 1)
2101                  {
2102                      // Moving into a forum that does count post counts
2103                      ++$user_counters[$post['uid']]['postnum'];
2104                  }
2105  
2106                  // Add 1 to the new thread's replies
2107                  ++$thread_counters[$newtid]['replies'];
2108              }
2109              elseif($post['visible'] == 0)
2110              {
2111                  // Unapproved post
2112                  // Add 1 to the new thread's unapproved posts
2113                  ++$thread_counters[$newtid]['unapprovedposts'];
2114              }
2115              elseif($post['visible'] == -1)
2116              {
2117                  // Soft deleted post
2118                  // Add 1 to the new thread's deleted posts
2119                  ++$thread_counters[$newtid]['deletedposts'];
2120              }
2121  
2122              // Add 1 to the new forum's posts
2123              if($newthread['visible'] == 1 && $post['visible'] == 1)
2124              {
2125                  ++$forum_counters[$moveto]['posts'];
2126              }
2127              elseif($newthread['visible'] == 0 || ($post['visible'] == 0 && $newthread['visible'] == 1))
2128              {
2129                  ++$forum_counters[$moveto]['unapprovedposts'];
2130              }
2131              else
2132              {
2133                  ++$forum_counters[$moveto]['deletedposts'];
2134              }
2135          }
2136  
2137          // Attach moved posts to the first post
2138          $db->update_query("posts", array('replyto' => $post_info['pid']), "tid='{$newtid}' AND replyto = 0 AND pid != '{$post_info['pid']}'");
2139  
2140          if($destination_tid == 0 && $newthread['visible'] == 1)
2141          {
2142              // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post
2143              --$thread_counters[$newtid]['replies'];
2144          }
2145          elseif($destination_tid == 0 && $newthread['visible'] == 0)
2146          {
2147              // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post
2148              --$thread_counters[$newtid]['unapprovedposts'];
2149          }
2150          elseif($destination_tid == 0 && $newthread['visible'] == -1)
2151          {
2152              // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post
2153              --$thread_counters[$newtid]['deletedposts'];
2154          }
2155  
2156          $arguments = array("pids" => $pids, "tid" => $tid, "moveto" => $moveto, "newsubject" => $newsubject, "destination_tid" => $destination_tid);
2157          $plugins->run_hooks("class_moderation_split_posts", $arguments);
2158  
2159          // Update user post counts
2160          if(!empty($user_counters))
2161          {
2162              foreach($user_counters as $uid => $counters)
2163              {
2164                  foreach($counters as $key => $counter)
2165                  {
2166                      if($counter >= 0)
2167                      {
2168                          $counters[$key] = "+{$counter}"; // add the addition operator for query
2169                      }
2170                  }
2171                  update_user_counters($uid, $counters);
2172              }
2173          }
2174  
2175          // Update thread counters
2176          if(is_array($thread_counters))
2177          {
2178              foreach($thread_counters as $tid => $counters)
2179              {
2180                  if($tid == $newtid)
2181                  {
2182                      // Update the subject of the first post in the new thread
2183                      $query = $db->simple_select("posts", "pid", "tid='$newtid'", array('order_by' => 'dateline, pid', 'limit' => 1));
2184                      $newthread = $db->fetch_array($query);
2185                      $sqlarray = array(
2186                          "subject" => $newsubject,
2187                          "replyto" => 0
2188                      );
2189                      $db->update_query("posts", $sqlarray, "pid='{$newthread['pid']}'");
2190                  }
2191                  else
2192                  {
2193                      // Update the subject of the first post in the old thread
2194                      $query = $db->query("
2195                          SELECT p.pid, t.subject
2196                          FROM ".TABLE_PREFIX."posts p
2197                          LEFT JOIN ".TABLE_PREFIX."threads t ON (p.tid=t.tid)
2198                          WHERE p.tid='{$tid}'
2199                          ORDER BY p.dateline ASC, p.pid ASC
2200                          LIMIT 1
2201                      ");
2202                      $oldthread = $db->fetch_array($query);
2203                      $sqlarray = array(
2204                          "subject" => $db->escape_string($oldthread['subject']),
2205                          "replyto" => 0
2206                      );
2207                      $db->update_query("posts", $sqlarray, "pid='{$oldthread['pid']}'");
2208                  }
2209  
2210                  foreach($counters as $key => $counter)
2211                  {
2212                      if($counter >= 0)
2213                      {
2214                          $counters[$key] = "+{$counter}";
2215                      }
2216                  }
2217                  update_thread_counters($tid, $counters);
2218                  update_last_post($tid);
2219              }
2220          }
2221  
2222          // Update forum counters
2223          if(!empty($forum_counters))
2224          {
2225              foreach($forum_counters as $fid => $counters)
2226              {
2227                  foreach($counters as $key => $counter)
2228                  {
2229                      if($counter >= 0)
2230                      {
2231                          $counters[$key] = "+{$counter}";
2232                      }
2233                  }
2234                  update_forum_counters($fid, $counters);
2235                  update_forum_lastpost($fid);
2236              }
2237          }
2238  
2239          return $newtid;
2240      }
2241  
2242      /**
2243       * Move multiple threads to new forum
2244       *
2245       * @param array $tids Thread IDs
2246       * @param int $moveto Destination forum
2247       * @return boolean
2248       *
2249       * @deprecated Iterate over move_thread instead
2250       */
2251  	function move_threads($tids, $moveto)
2252      {
2253          global $db, $plugins;
2254  
2255          // Make sure we only have valid values
2256          $tids = array_map('intval', $tids);
2257  
2258          $tid_list = implode(',', $tids);
2259  
2260          $moveto = (int)$moveto;
2261  
2262          $newforum = get_forum($moveto);
2263  
2264          if(empty($tids) || !$newforum)
2265          {
2266              return false;
2267          }
2268  
2269          $total_posts = $total_unapproved_posts = $total_deleted_posts = $total_threads = $total_unapproved_threads = $total_deleted_threads = 0;
2270          $forum_counters = $user_counters = array();
2271          $query = $db->simple_select("threads", "fid, visible, replies, unapprovedposts, deletedposts, tid, uid", "tid IN ($tid_list)");
2272          while($thread = $db->fetch_array($query))
2273          {
2274              $forum = get_forum($thread['fid']);
2275  
2276              if(!isset($forum_counters[$thread['fid']]))
2277              {
2278                  $forum_counters[$thread['fid']] = array(
2279                      'posts' => 0,
2280                      'threads' => 0,
2281                      'unapprovedposts' => 0,
2282                      'unapprovedthreads' => 0,
2283                      'deletedthreads' => 0,
2284                      'deletedposts' => 0
2285                  );
2286              }
2287  
2288              if(!isset($user_counters[$thread['uid']]))
2289              {
2290                  $user_counters[$thread['uid']] = array(
2291                      'num_posts' => 0,
2292                      'num_threads' => 0
2293                  );
2294              }
2295  
2296              if($thread['visible'] == 1)
2297              {
2298                  $total_posts += $thread['replies']+1;
2299                  $total_unapproved_posts += $thread['unapprovedposts'];
2300                  $total_deleted_posts += $thread['deletedposts'];
2301                  $forum_counters[$thread['fid']]['posts'] += $thread['replies']+1;
2302                  $forum_counters[$thread['fid']]['unapprovedposts'] += $thread['unapprovedposts'];
2303                  $forum_counters[$thread['fid']]['deletedposts'] += $thread['deletedposts'];
2304  
2305                  $forum_counters[$thread['fid']]['threads']++;
2306                  ++$total_threads;
2307  
2308                  if($newforum['usethreadcounts'] == 1 && $forum['usethreadcounts'] == 0)
2309                  {
2310                      ++$user_counters[$thread['uid']]['num_threads'];
2311                  }
2312                  else if($newforum['usethreadcounts'] == 0 && $forum['usethreadcounts'] == 1)
2313                  {
2314                      --$user_counters[$thread['uid']]['num_threads'];
2315                  }
2316  
2317                  $query1 = $db->query("
2318                      SELECT COUNT(p.pid) AS posts, u.uid
2319                      FROM ".TABLE_PREFIX."posts p
2320                      LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid)
2321                      WHERE p.tid = '{$thread['tid']}' AND p.visible=1
2322                      GROUP BY u.uid
2323                      ORDER BY posts DESC
2324                  ");
2325                  while($posters = $db->fetch_array($query1))
2326                  {
2327                      if(!isset($user_counters[$posters['uid']]))
2328                      {
2329                          $user_counters[$posters['uid']] = array(
2330                              'num_posts' => 0,
2331                              'num_threads' => 0
2332                          );
2333                      }
2334  
2335                      if($newforum['usepostcounts'] != 0 && $forum['usepostcounts'] == 0)
2336                      {
2337                          $user_counters[$posters['uid']]['num_posts'] += $posters['posts'];
2338                      }
2339                      else if($newforum['usepostcounts'] == 0 && $forum['usepostcounts'] != 0)
2340                      {
2341                          $user_counters[$posters['uid']]['num_posts'] -= $posters['posts'];
2342                      }
2343                  }
2344              }
2345              elseif($thread['visible'] == -1)
2346              {
2347                  $total_deleted_posts += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1;
2348  
2349                  $forum_counters[$thread['fid']]['deletedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Implied deleted posts counter for deleted threads
2350  
2351                  $forum_counters[$thread['fid']]['deletedthreads']++;
2352                  ++$total_deleted_threads;
2353              }
2354              else
2355              {
2356                  $total_unapproved_posts += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1;
2357  
2358                  $forum_counters[$thread['fid']]['unapprovedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Implied unapproved posts counter for unapproved threads
2359  
2360                  $forum_counters[$thread['fid']]['unapprovedthreads']++;
2361                  ++$total_unapproved_threads;
2362              }
2363  
2364              // Remove old redirects
2365              $redirects_query = $db->simple_select('threads', 'tid', "closed='moved|{$thread['tid']}' AND fid='$moveto'");
2366              while($redirect_tid = $db->fetch_field($redirects_query, 'tid'))
2367              {
2368                  $this->delete_thread($redirect_tid);
2369              }
2370          }
2371  
2372          $sqlarray = array(
2373              "fid" => $moveto,
2374          );
2375          $db->update_query("threads", $sqlarray, "tid IN ($tid_list)");
2376          $db->update_query("posts", $sqlarray, "tid IN ($tid_list)");
2377  
2378          // If any of the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix
2379          $query = $db->simple_select("threads", "tid, prefix", "tid IN ($tid_list) AND prefix != 0");
2380          while($thread = $db->fetch_array($query))
2381          {
2382              switch($db->type)
2383              {
2384                  case "pgsql":
2385                  case "sqlite":
2386                      $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$moveto,%' OR forums='-1') AND pid='".$thread['prefix']."'");
2387                      break;
2388                  default:
2389                      $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$moveto,%' OR forums='-1') AND pid='".$thread['prefix']."'");
2390              }
2391              if($db->fetch_field($query, "num_prefixes") == 0)
2392              {
2393                  $sqlarray = array(
2394                      "prefix" => 0,
2395                  );
2396                  $db->update_query("threads", $sqlarray, "tid = '{$thread['tid']}'");
2397              }
2398          }
2399  
2400          $arguments = array("tids" => $tids, "moveto" => $moveto);
2401          $plugins->run_hooks("class_moderation_move_threads", $arguments);
2402  
2403          if(!empty($user_counters))
2404          {
2405              foreach($user_counters as $uid => $counters)
2406              {
2407                  $update_array = array(
2408                      "postnum" => "+{$counters['num_posts']}",
2409                      "threadnum" => "+{$counters['num_threads']}",
2410                  );
2411                  update_user_counters($uid, $update_array);
2412              }
2413          }
2414  
2415          if(is_array($forum_counters))
2416          {
2417              foreach($forum_counters as $fid => $counter)
2418              {
2419                  $updated_count = array(
2420                      'posts' => "-{$counter['posts']}",
2421                      'threads' => "-{$counter['threads']}",
2422                      'unapprovedposts' => "-{$counter['unapprovedposts']}",
2423                      'unapprovedthreads' => "-{$counter['unapprovedthreads']}",
2424                      'deletedposts' => "-{$counter['deletedposts']}",
2425                      'deletedthreads' => "-{$counter['deletedthreads']}"
2426  
2427                  );
2428                  update_forum_counters($fid, $updated_count);
2429                  update_forum_lastpost($fid);
2430              }
2431          }
2432  
2433          $updated_count = array(
2434              "threads" => "+{$total_threads}",
2435              "unapprovedthreads" => "+{$total_unapproved_threads}",
2436              "posts" => "+{$total_posts}",
2437              "unapprovedposts" => "+{$total_unapproved_posts}",
2438              'deletedposts' => "+{$total_deleted_posts}",
2439              "deletedthreads" => "+{$total_deleted_threads}"
2440          );
2441  
2442          update_forum_counters($moveto, $updated_count);
2443          update_forum_lastpost($moveto);
2444  
2445          // Remove thread subscriptions for the users who no longer have permission to view the thread
2446          $this->remove_thread_subscriptions($tid_list, false, $moveto);
2447  
2448          return true;
2449      }
2450  
2451      /**
2452       * Approve multiple posts
2453       *
2454       * @param array $pids PIDs
2455       * @return boolean
2456       */
2457  	function approve_posts($pids)
2458      {
2459          global $db, $cache, $plugins;
2460  
2461          $num_posts = 0;
2462  
2463          if(empty($pids))
2464          {
2465              return false;
2466          }
2467  
2468          // Make sure we only have valid values
2469          $pids = array_map('intval', $pids);
2470  
2471          $pid_list = implode(',', $pids);
2472          $pids = $threads_to_update = array();
2473  
2474          // Make visible
2475          $approve = array(
2476              "visible" => 1,
2477          );
2478  
2479          // We have three cases we deal with in these code segments:
2480          // 1) We're approving specific unapproved posts
2481          // 1.1) if the thread is approved
2482          // 1.2) if the thread is unapproved
2483          // 2) We're approving the firstpost of the thread, therefore approving the thread itself
2484          // 3) We're doing both 1 and 2
2485          $query = $db->query("
2486              SELECT p.tid
2487              FROM ".TABLE_PREFIX."posts p
2488              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
2489              WHERE p.pid IN ($pid_list) AND p.visible = '0' AND t.firstpost = p.pid AND t.visible = 0
2490          ");
2491          while($post = $db->fetch_array($query))
2492          {
2493              // This is the first post in the thread so we're approving the whole thread.
2494              $threads_to_update[] = $post['tid'];
2495          }
2496  
2497          if(!empty($threads_to_update))
2498          {
2499              $this->approve_threads($threads_to_update);
2500          }
2501  
2502          $thread_counters = $forum_counters = $user_counters = array();
2503  
2504          $query = $db->query("
2505              SELECT p.pid, p.tid, p.fid, p.uid, t.visible AS threadvisible
2506              FROM ".TABLE_PREFIX."posts p
2507              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
2508              WHERE p.pid IN ($pid_list) AND p.visible = '0' AND t.firstpost != p.pid
2509          ");
2510          while($post = $db->fetch_array($query))
2511          {
2512              $pids[] = $post['pid'];
2513  
2514              if(!isset($thread_counters[$post['tid']]))
2515              {
2516                  $thread_counters[$post['tid']] = array(
2517                      'replies' => 0
2518                  );
2519              }
2520  
2521              ++$thread_counters[$post['tid']]['replies'];
2522  
2523              // If the thread of this post is unapproved then we've already taken into account this counter as implied.
2524              // Updating it again would cause it to double count
2525              if($post['threadvisible'] == 1)
2526              {
2527                  if(!isset($forum_counters[$post['fid']]))
2528                  {
2529                      $forum_counters[$post['fid']] = array(
2530                          'num_posts' => 0
2531                      );
2532                  }
2533                  ++$forum_counters[$post['fid']]['num_posts'];
2534              }
2535  
2536              $forum = get_forum($post['fid']);
2537  
2538              // If post counts enabled in this forum and the thread is approved, add 1
2539              if($forum['usepostcounts'] != 0 && $post['threadvisible'] == 1)
2540              {
2541                  if(!isset($user_counters[$post['uid']]))
2542                  {
2543                      $user_counters[$post['uid']] = 0;
2544                  }
2545                  ++$user_counters[$post['uid']];
2546              }
2547          }
2548  
2549          if(empty($pids) && empty($threads_to_update))
2550          {
2551              return false;
2552          }
2553  
2554          if(!empty($pids))
2555          {
2556              $where = "pid IN (".implode(',', $pids).")";
2557              $db->update_query("posts", $approve, $where);
2558          }
2559  
2560          $plugins->run_hooks("class_moderation_approve_posts", $pids);
2561  
2562          if(!empty($thread_counters))
2563          {
2564              foreach($thread_counters as $tid => $counters)
2565              {
2566                  $counters_update = array(
2567                      "unapprovedposts" => "-".$counters['replies'],
2568                      "replies" => "+".$counters['replies']
2569                  );
2570                  update_thread_counters($tid, $counters_update);
2571                  update_last_post($tid);
2572              }
2573          }
2574  
2575          if(!empty($forum_counters))
2576          {
2577              foreach($forum_counters as $fid => $counters)
2578              {
2579                  $updated_forum_stats = array(
2580                      'posts' => "+{$counters['num_posts']}",
2581                      'unapprovedposts' => "-{$counters['num_posts']}",
2582                  );
2583                  update_forum_counters($fid, $updated_forum_stats);
2584                  update_forum_lastpost($fid);
2585              }
2586          }
2587  
2588          if(!empty($user_counters))
2589          {
2590              foreach($user_counters as $uid => $counter)
2591              {
2592                  update_user_counters($uid, array('postnum' => "+{$counter}"));
2593              }
2594          }
2595  
2596          return true;
2597      }
2598  
2599      /**
2600       * Unapprove multiple posts
2601       *
2602       * @param array $pids PIDs
2603       * @return boolean
2604       */
2605  	function unapprove_posts($pids)
2606      {
2607          global $db, $cache, $plugins;
2608  
2609          if(empty($pids))
2610          {
2611              return false;
2612          }
2613  
2614          // Make sure we only have valid values
2615          $pids = array_map('intval', $pids);
2616  
2617          $pid_list = implode(',', $pids);
2618          $pids = $threads_to_update = array();
2619  
2620          // Make invisible
2621          $approve = array(
2622              "visible" => 0,
2623          );
2624  
2625          // We have three cases we deal with in these code segments:
2626          // 1) We're unapproving specific approved posts
2627          // 1.1) if the thread is approved
2628          // 1.2) if the thread is unapproved
2629          // 1.3) if the thread is deleted
2630          // 2) We're unapproving the firstpost of the thread, therefore unapproving the thread itself
2631          // 3) We're doing both 1 and 2
2632          $query = $db->query("
2633              SELECT p.tid
2634              FROM ".TABLE_PREFIX."posts p
2635              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
2636              WHERE p.pid IN ($pid_list) AND p.visible IN (-1,1) AND t.firstpost = p.pid AND t.visible IN (-1,1)
2637          ");
2638          while($post = $db->fetch_array($query))
2639          {
2640              // This is the first post in the thread so we're unapproving the whole thread.
2641              $threads_to_update[] = $post['tid'];
2642          }
2643  
2644          if(!empty($threads_to_update))
2645          {
2646              $this->unapprove_threads($threads_to_update);
2647          }
2648  
2649          $thread_counters = $forum_counters = $user_counters = array();
2650  
2651          $query = $db->query("
2652              SELECT p.pid, p.tid, p.visible, p.fid, p.uid, t.visible AS threadvisible
2653              FROM ".TABLE_PREFIX."posts p
2654              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
2655              WHERE p.pid IN ($pid_list) AND p.visible IN (-1,1) AND t.firstpost != p.pid
2656          ");
2657          while($post = $db->fetch_array($query))
2658          {
2659              $pids[] = $post['pid'];
2660  
2661              if(!isset($thread_counters[$post['tid']]))
2662              {
2663                  $thread_counters[$post['tid']] = array(
2664                      'replies' => 0,
2665                      'unapprovedposts' => 0,
2666                      'deletedposts' => 0
2667                  );
2668              }
2669  
2670              ++$thread_counters[$post['tid']]['unapprovedposts'];
2671              if($post['visible'] == 1)
2672              {
2673                  ++$thread_counters[$post['tid']]['replies'];
2674              }
2675              else
2676              {
2677                  ++$thread_counters[$post['tid']]['deletedposts'];
2678              }
2679  
2680              if(!isset($forum_counters[$post['fid']]))
2681              {
2682                  $forum_counters[$post['fid']] = array(
2683                      'num_posts' => 0,
2684                      'num_unapproved_posts' => 0,
2685                      'num_deleted_posts' => 0
2686                  );
2687              }
2688  
2689              // If the thread of this post is unapproved then we've already taken into account this counter as implied.
2690              // Updating it again would cause it to double count
2691              if($post['threadvisible'] != 0)
2692              {
2693                  ++$forum_counters[$post['fid']]['num_unapproved_posts'];
2694                  if($post['visible'] == 1)
2695                  {
2696                      ++$forum_counters[$post['fid']]['num_posts'];
2697                  }
2698                  else
2699                  {
2700                      ++$forum_counters[$post['fid']]['num_deleted_posts'];
2701                  }
2702              }
2703  
2704              $forum = get_forum($post['fid']);
2705  
2706              // If post counts enabled in this forum and the thread is approved, subtract 1
2707              if($forum['usepostcounts'] != 0 && $post['visible'] == 1 && $post['threadvisible'] == 1)
2708              {
2709                  if(!isset($user_counters[$post['uid']]))
2710                  {
2711                      $user_counters[$post['uid']] = 0;
2712                  }
2713                  --$user_counters[$post['uid']];
2714              }
2715          }
2716  
2717          if(empty($pids) && empty($threads_to_update))
2718          {
2719              return false;
2720          }
2721  
2722          if(!empty($pids))
2723          {
2724              $where = "pid IN (".implode(',', $pids).")";
2725              $db->update_query("posts", $approve, $where);
2726          }
2727  
2728          $plugins->run_hooks("class_moderation_unapprove_posts", $pids);
2729  
2730          if(!empty($thread_counters))
2731          {
2732              foreach($thread_counters as $tid => $counters)
2733              {
2734                  $counters_update = array(
2735                      "unapprovedposts" => "+".$counters['unapprovedposts'],
2736                      "replies" => "-".$counters['replies'],
2737                      "deletedposts" => "-".$counters['deletedposts']
2738                  );
2739  
2740                  update_thread_counters($tid, $counters_update);
2741                  update_last_post($tid);
2742              }
2743          }
2744  
2745          if(!empty($forum_counters))
2746          {
2747              foreach($forum_counters as $fid => $counters)
2748              {
2749                  $updated_forum_stats = array(
2750                      'posts' => "-{$counters['num_posts']}",
2751                      'unapprovedposts' => "+{$counters['num_unapproved_posts']}",
2752                      'deletedposts' => "-{$counters['num_deleted_posts']}"
2753                  );
2754                  update_forum_counters($fid, $updated_forum_stats);
2755                  update_forum_lastpost($fid);
2756              }
2757          }
2758  
2759          if(!empty($user_counters))
2760          {
2761              foreach($user_counters as $uid => $counter)
2762              {
2763                  update_user_counters($uid, array('postnum' => "{$counter}"));
2764              }
2765          }
2766  
2767          return true;
2768      }
2769  
2770      /**
2771       * Change thread subject
2772       *
2773       * @param int|array $tids Thread ID(s)
2774       * @param string $format Format of new subject (with {subject})
2775       * @return boolean
2776       */
2777  	function change_thread_subject($tids, $format)
2778      {
2779          global $db, $mybb, $plugins;
2780  
2781          // Get tids into list
2782          if(!is_array($tids))
2783          {
2784              $tids = array($tids);
2785          }
2786  
2787          // Make sure we only have valid values
2788          $tids = array_map('intval', $tids);
2789  
2790          if(empty($tids))
2791          {
2792              return false;
2793          }
2794  
2795          $tid_list = implode(',', $tids);
2796  
2797          // Get original subject
2798          $query = $db->query("
2799              SELECT u.uid, u.username, t.tid, t.subject FROM ".TABLE_PREFIX."threads t
2800              LEFT JOIN ".TABLE_PREFIX."users u ON t.uid=u.uid
2801              WHERE tid IN ($tid_list)
2802          ");
2803          while($thread = $db->fetch_array($query))
2804          {
2805              // Update threads and first posts with new subject
2806              $find = array('{username}', 'author', '{subject}');
2807              $replace = array($mybb->user['username'], $thread['username'], $thread['subject']);
2808  
2809              $new_subject = str_ireplace($find, $replace, $format);
2810  
2811              $args = array(
2812                  'thread' => &$thread,
2813                  'new_subject' => &$new_subject,
2814              );
2815  
2816              $plugins->run_hooks("class_moderation_change_thread_subject_newsubject", $args);
2817  
2818              $update_subject = array(
2819                  "subject" => $db->escape_string($new_subject)
2820              );
2821              $db->update_query("threads", $update_subject, "tid='{$thread['tid']}'");
2822              $db->update_query("posts", $update_subject, "tid='{$thread['tid']}' AND replyto='0'");
2823          }
2824  
2825          $arguments = array("tids" => $tids, "format" => $format);
2826          $plugins->run_hooks("class_moderation_change_thread_subject", $arguments);
2827  
2828          return true;
2829      }
2830  
2831      /**
2832       * Add thread expiry
2833       *
2834       * @param int $tid Thread ID
2835       * @param int $deletetime Timestamp when the thread is deleted
2836       * @return boolean
2837       */
2838  	function expire_thread($tid, $deletetime)
2839      {
2840          global $db, $plugins;
2841  
2842          $tid = (int)$tid;
2843  
2844          if(empty($tid))
2845          {
2846              return false;
2847          }
2848  
2849          $update_thread = array(
2850              "deletetime" => (int)$deletetime
2851          );
2852          $db->update_query("threads", $update_thread, "tid='{$tid}'");
2853  
2854          $arguments = array("tid" => $tid, "deletetime" => $deletetime);
2855          $plugins->run_hooks("class_moderation_expire_thread", $arguments);
2856  
2857          return true;
2858      }
2859  
2860      /**
2861       * Toggle post visibility (approved/unapproved)
2862       *
2863       * @param array $pids Post IDs
2864       * @return boolean true
2865       */
2866  	function toggle_post_visibility($pids)
2867      {
2868          global $db;
2869  
2870          // Make sure we only have valid values
2871          $pids = array_map('intval', $pids);
2872  
2873          $pid_list = implode(',', $pids);
2874          $query = $db->simple_select("posts", 'pid, visible', "pid IN ($pid_list)");
2875          while($post = $db->fetch_array($query))
2876          {
2877              if($post['visible'] != 0)
2878              {
2879                  $unapprove[] = $post['pid'];
2880              }
2881              else
2882              {
2883                  $approve[] = $post['pid'];
2884              }
2885          }
2886          if(is_array($unapprove))
2887          {
2888              $this->unapprove_posts($unapprove);
2889          }
2890          if(is_array($approve))
2891          {
2892              $this->approve_posts($approve);
2893          }
2894          return true;
2895      }
2896  
2897      /**
2898       * Toggle post visibility (deleted/restored)
2899       *
2900       * @param array $pids Post IDs
2901       * @return boolean true
2902       */
2903  	function toggle_post_softdelete($pids)
2904      {
2905          global $db;
2906  
2907          // Make sure we only have valid values
2908          $pids = array_map('intval', $pids);
2909  
2910          $pid_list = implode(',', $pids);
2911          $query = $db->simple_select("posts", 'pid, visible', "pid IN ($pid_list)");
2912          while($post = $db->fetch_array($query))
2913          {
2914              if($post['visible'] != -1)
2915              {
2916                  $delete[] = $post['pid'];
2917              }
2918              else
2919              {
2920                  $restore[] = $post['pid'];
2921              }
2922          }
2923          if(is_array($delete))
2924          {
2925              $this->soft_delete_posts($delete);
2926          }
2927          if(is_array($restore))
2928          {
2929              $this->restore_posts($restore);
2930          }
2931          return true;
2932      }
2933  
2934      /**
2935       * Toggle thread visibility (approved/unapproved)
2936       *
2937       * @param array $tids Thread IDs
2938       * @param int $fid Forum ID
2939       * @return boolean true
2940       */
2941  	function toggle_thread_visibility($tids, $fid)
2942      {
2943          global $db;
2944  
2945          // Make sure we only have valid values
2946          $tids = array_map('intval', $tids);
2947          $fid = (int)$fid;
2948  
2949          $tid_list = implode(',', $tids);
2950          $query = $db->simple_select("threads", 'tid, visible', "tid IN ($tid_list)");
2951          while($thread = $db->fetch_array($query))
2952          {
2953              if($thread['visible'] != 0)
2954              {
2955                  $unapprove[] = $thread['tid'];
2956              }
2957              else
2958              {
2959                  $approve[] = $thread['tid'];
2960              }
2961          }
2962          if(is_array($unapprove))
2963          {
2964              $this->unapprove_threads($unapprove, $fid);
2965          }
2966          if(is_array($approve))
2967          {
2968              $this->approve_threads($approve, $fid);
2969          }
2970          return true;
2971      }
2972  
2973      /**
2974       * Toggle thread visibility (deleted/restored)
2975       *
2976       * @param array $tids Thread IDs
2977       * @return boolean true
2978       */
2979  	function toggle_thread_softdelete($tids)
2980      {
2981          global $db;
2982  
2983          // Make sure we only have valid values
2984          $tids = array_map('intval', $tids);
2985  
2986          $tid_list = implode(',', $tids);
2987          $query = $db->simple_select("threads", 'tid, visible', "tid IN ($tid_list)");
2988          while($thread = $db->fetch_array($query))
2989          {
2990              if($thread['visible'] != -1)
2991              {
2992                  $delete[] = $thread['tid'];
2993              }
2994              else
2995              {
2996                  $restore[] = $thread['tid'];
2997              }
2998          }
2999          if(is_array($delete))
3000          {
3001              $this->soft_delete_threads($delete);
3002          }
3003          if(is_array($restore))
3004          {
3005              $this->restore_threads($restore);
3006          }
3007          return true;
3008      }
3009  
3010      /**
3011       * Toggle threads open/closed
3012       *
3013       * @param array $tids Thread IDs
3014       * @return boolean true
3015       */
3016  	function toggle_thread_status($tids)
3017      {
3018          global $db;
3019  
3020          // Make sure we only have valid values
3021          $tids = array_map('intval', $tids);
3022  
3023          $tid_list = implode(',', $tids);
3024          $query = $db->simple_select("threads", 'tid, closed', "tid IN ($tid_list)");
3025          while($thread = $db->fetch_array($query))
3026          {
3027              if($thread['closed'] == 1)
3028              {
3029                  $open[] = $thread['tid'];
3030              }
3031              elseif($thread['closed'] == 0)
3032              {
3033                  $close[] = $thread['tid'];
3034              }
3035          }
3036          if(is_array($open))
3037          {
3038              $this->open_threads($open);
3039          }
3040          if(is_array($close))
3041          {
3042              $this->close_threads($close);
3043          }
3044          return true;
3045      }
3046  
3047      /**
3048       * Toggle threads stick/unstick
3049       *
3050       * @param array $tids Thread IDs
3051       * @return boolean true
3052       */
3053  	function toggle_thread_importance($tids)
3054      {
3055          global $db;
3056  
3057          // Make sure we only have valid values
3058          $tids = array_map('intval', $tids);
3059  
3060          $stick = array();
3061          $unstick = array();
3062  
3063          $tid_list = implode(',', $tids);
3064          $query = $db->simple_select("threads", 'tid, sticky', "tid IN ($tid_list)");
3065          while($thread = $db->fetch_array($query))
3066          {
3067              if($thread['sticky'] == 0)
3068              {
3069                  $stick[] = $thread['tid'];
3070              }
3071              elseif($thread['sticky'] == 1)
3072              {
3073                  $unstick[] = $thread['tid'];
3074              }
3075          }
3076          if(!empty($stick))
3077          {
3078              $this->stick_threads($stick);
3079          }
3080          if(!empty($unstick))
3081          {
3082              $this->unstick_threads($unstick);
3083          }
3084          return true;
3085      }
3086  
3087      /**
3088       * Remove thread subscriptions (from one or multiple threads in the same forum)
3089       *
3090       * @param int|array $tids Thread ID, or an array of thread IDs from the same forum.
3091       * @param boolean $all True (default) to delete all subscriptions, false to only delete subscriptions from users with no permission to read the thread
3092       * @param int $fid (Only applies if $all is false) The forum ID of the thread
3093       * @return boolean
3094       */
3095  	function remove_thread_subscriptions($tids, $all = true, $fid = 0)
3096      {
3097          global $db, $plugins;
3098  
3099          // Format thread IDs
3100          if(!is_array($tids))
3101          {
3102              $tids = array($tids);
3103          }
3104  
3105          if(empty($tids))
3106          {
3107              return false;
3108          }
3109  
3110          // Make sure we only have valid values
3111          $tids = array_map('intval', $tids);
3112          $fid = (int)$fid;
3113  
3114          $tids_csv = implode(',', $tids);
3115  
3116          // Delete only subscriptions from users who no longer have permission to read the thread.
3117          if(!$all)
3118          {
3119              // Get groups that cannot view the forum or its threads
3120              $forum_parentlist = get_parent_list($fid);
3121              $query = $db->simple_select("forumpermissions", "gid", "fid IN ({$forum_parentlist}) AND (canview=0 OR canviewthreads=0)");
3122              $groups = array();
3123              $additional_groups = '';
3124              while($group = $db->fetch_array($query))
3125              {
3126                  $groups[] = $group['gid'];
3127                  switch($db->type)
3128                  {
3129                      case "pgsql":
3130                      case "sqlite":
3131                          $additional_groups .= " OR ','||u.additionalgroups||',' LIKE ',{$group['gid']},'";
3132                          break;
3133                      default:
3134                          $additional_groups .= " OR CONCAT(',',u.additionalgroups,',') LIKE ',{$group['gid']},'";
3135                  }
3136              }
3137              // If there are groups found, delete subscriptions from users in these groups
3138              if(count($groups) > 0)
3139              {
3140                  $groups_csv = implode(',', $groups);
3141                  $query = $db->query("
3142                      SELECT s.tid, u.uid
3143                      FROM ".TABLE_PREFIX."threadsubscriptions s
3144                      LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=s.uid)
3145                      WHERE s.tid IN ({$tids_csv})
3146                      AND (u.usergroup IN ({$groups_csv}){$additional_groups})
3147                  ");
3148                  while($subscription = $db->fetch_array($query))
3149                  {
3150                      $db->delete_query("threadsubscriptions", "uid='{$subscription['uid']}' AND tid='{$subscription['tid']}'");
3151                  }
3152              }
3153          }
3154          // Delete all subscriptions of this thread
3155          else
3156          {
3157              $db->delete_query("threadsubscriptions", "tid IN ({$tids_csv})");
3158          }
3159  
3160          $arguments = array("tids" => $tids, "all" => $all, "fid" => $fid);
3161          $plugins->run_hooks("class_moderation_remove_thread_subscriptions", $arguments);
3162  
3163          return true;
3164      }
3165  
3166      /**
3167       * Apply a thread prefix (to one or multiple threads in the same forum)
3168       *
3169       * @param int|array $tids Thread ID, or an array of thread IDs from the same forum.
3170       * @param int $prefix Prefix ID to apply to the threads
3171       * @return bool
3172       */
3173  	function apply_thread_prefix($tids, $prefix = 0)
3174      {
3175          global $db, $plugins;
3176  
3177          // Format thread IDs
3178          if(!is_array($tids))
3179          {
3180              $tids = array($tids);
3181          }
3182  
3183          if(empty($tids))
3184          {
3185              return false;
3186          }
3187  
3188          // Make sure we only have valid values
3189          $tids = array_map('intval', $tids);
3190          $tids_csv = implode(',', $tids);
3191  
3192          $update_thread = array('prefix' => (int)$prefix);
3193          $db->update_query('threads', $update_thread, "tid IN ({$tids_csv})");
3194  
3195          $arguments = array('tids' => $tids, 'prefix' => $prefix);
3196  
3197          $plugins->run_hooks('class_moderation_apply_thread_prefix', $arguments);
3198  
3199          return true;
3200      }
3201  
3202      /**
3203       * Soft delete multiple posts
3204       *
3205       * @param array $pids PIDs
3206       * @return boolean
3207       */
3208  	function soft_delete_posts($pids)
3209      {
3210          global $db, $cache, $plugins;
3211  
3212          if(empty($pids))
3213          {
3214              return false;
3215          }
3216  
3217          // Make sure we only have valid values
3218          $pids = array_map('intval', $pids);
3219  
3220          $pid_list = implode(',', $pids);
3221          $pids = $threads_to_update = array();
3222  
3223          // Make invisible
3224          $update = array(
3225              "visible" => -1,
3226          );
3227  
3228          // We have three cases we deal with in these code segments:
3229          // 1) We're deleting specific approved posts
3230          // 1.1) if the thread is approved
3231          // 1.2) if the thread is unapproved
3232          // 1.3) if the thread is deleted
3233          // 2) We're deleting the firstpost of the thread, therefore deleting the thread itself
3234          // 3) We're doing both 1 and 2
3235          $query = $db->query("
3236              SELECT p.tid
3237              FROM ".TABLE_PREFIX."posts p
3238              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
3239              WHERE p.pid IN ($pid_list) AND p.visible IN (0,1) AND t.firstpost = p.pid AND t.visible IN (0,1)
3240          ");
3241          while($post = $db->fetch_array($query))
3242          {
3243              // This is the first post in the thread so we're deleting the whole thread.
3244              $threads_to_update[] = $post['tid'];
3245          }
3246  
3247          if(!empty($threads_to_update))
3248          {
3249              $this->soft_delete_threads($threads_to_update);
3250          }
3251  
3252          $thread_counters = $forum_counters = $user_counters = array();
3253  
3254          $query = $db->query("
3255              SELECT p.pid, p.tid, p.visible, f.fid, f.usepostcounts, p.uid, t.visible AS threadvisible
3256              FROM ".TABLE_PREFIX."posts p
3257              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
3258              LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid)
3259              WHERE p.pid IN ($pid_list) AND p.visible IN (0,1) AND t.firstpost != p.pid
3260          ");
3261          while($post = $db->fetch_array($query))
3262          {
3263              $pids[] = $post['pid'];
3264  
3265              if(!isset($thread_counters[$post['tid']]))
3266              {
3267                  $thread_counters[$post['tid']] = array(
3268                      'replies' => 0,
3269                      'unapprovedposts' => 0,
3270                      'deletedposts' => 0
3271                  );
3272              }
3273  
3274              ++$thread_counters[$post['tid']]['deletedposts'];
3275              if($post['visible'] == 1)
3276              {
3277                  ++$thread_counters[$post['tid']]['replies'];
3278              }
3279              else
3280              {
3281                  ++$thread_counters[$post['tid']]['unapprovedposts'];
3282              }
3283  
3284              if(!isset($forum_counters[$post['fid']]))
3285              {
3286                  $forum_counters[$post['fid']] = array(
3287                      'num_posts' => 0,
3288                      'num_unapproved_posts' => 0,
3289                      'num_deleted_posts' => 0
3290                  );
3291              }
3292  
3293              // If the thread of this post is deleted then we've already taken into account this counter as implied.
3294              // Updating it again would cause it to double count
3295              if($post['threadvisible'] == 1)
3296              {
3297                  ++$forum_counters[$post['fid']]['num_deleted_posts'];
3298                  if($post['visible'] == 1)
3299                  {
3300                      ++$forum_counters[$post['fid']]['num_posts'];
3301                  }
3302                  else
3303                  {
3304                      ++$forum_counters[$post['fid']]['num_unapproved_posts'];
3305                  }
3306              }
3307  
3308              // If post counts enabled in this forum and the thread is approved, subtract 1
3309              if($post['usepostcounts'] != 0 && $post['threadvisible'] == 1 && $post['visible'] == 1)
3310              {
3311                  if(!isset($user_counters[$post['uid']]))
3312                  {
3313                      $user_counters[$post['uid']] = 0;
3314                  }
3315                  --$user_counters[$post['uid']];
3316              }
3317          }
3318  
3319          if(empty($pids) && empty($threads_to_update))
3320          {
3321              return false;
3322          }
3323  
3324          if(!empty($pids))
3325          {
3326              $where = "pid IN (".implode(',', $pids).")";
3327              $db->update_query("posts", $update, $where);
3328              mark_reports($pids, "posts");
3329          }
3330  
3331          $plugins->run_hooks("class_moderation_soft_delete_posts", $pids);
3332  
3333          if(is_array($thread_counters))
3334          {
3335              foreach($thread_counters as $tid => $counters)
3336              {
3337                  $counters_update = array(
3338                      "unapprovedposts" => "-".$counters['unapprovedposts'],
3339                      "replies" => "-".$counters['replies'],
3340                      "deletedposts" => "+".$counters['deletedposts']
3341                  );
3342  
3343                  update_thread_counters($tid, $counters_update);
3344                  update_last_post($tid);
3345              }
3346          }
3347  
3348          if(is_array($forum_counters))
3349          {
3350              foreach($forum_counters as $fid => $counters)
3351              {
3352                  $updated_forum_stats = array(
3353                      'posts' => "-{$counters['num_posts']}",
3354                      'unapprovedposts' => "-{$counters['num_unapproved_posts']}",
3355                      'deletedposts' => "+{$counters['num_deleted_posts']}"
3356                  );
3357                  update_forum_counters($fid, $updated_forum_stats);
3358                  update_forum_lastpost($fid);
3359              }
3360          }
3361  
3362          if(!empty($user_counters))
3363          {
3364              foreach($user_counters as $uid => $counter)
3365              {
3366                  update_user_counters($uid, array('postnum' => "{$counter}"));
3367              }
3368          }
3369  
3370          return true;
3371      }
3372  
3373      /**
3374       * Restore multiple posts
3375       *
3376       * @param array $pids PIDs
3377       * @return boolean
3378       */
3379  	function restore_posts($pids)
3380      {
3381          global $db, $cache, $plugins;
3382  
3383          $num_posts = 0;
3384  
3385          if(empty($pids))
3386          {
3387              return false;
3388          }
3389  
3390          // Make sure we only have valid values
3391          $pids = array_map('intval', $pids);
3392  
3393          $pid_list = implode(',', $pids);
3394          $pids = $threads_to_update = array();
3395  
3396          // Make visible
3397          $update = array(
3398              "visible" => 1,
3399          );
3400  
3401          // We have three cases we deal with in these code segments:
3402          // 1) We're approving specific restored posts
3403          // 1.1) if the thread is deleted
3404          // 1.2) if the thread is restored
3405          // 2) We're restoring the firstpost of the thread, therefore restoring the thread itself
3406          // 3) We're doing both 1 and 2
3407          $query = $db->query("
3408              SELECT p.tid
3409              FROM ".TABLE_PREFIX."posts p
3410              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
3411              WHERE p.pid IN ($pid_list) AND p.visible = '-1' AND t.firstpost = p.pid AND t.visible = -1
3412          ");
3413          while($post = $db->fetch_array($query))
3414          {
3415              // This is the first post in the thread so we're approving the whole thread.
3416              $threads_to_update[] = $post['tid'];
3417          }
3418  
3419          if(!empty($threads_to_update))
3420          {
3421              $this->restore_threads($threads_to_update);
3422          }
3423  
3424          $thread_counters = $forum_counters = $user_counters = array();
3425  
3426          $query = $db->query("
3427              SELECT p.pid, p.tid, f.fid, f.usepostcounts, p.uid, t.visible AS threadvisible
3428              FROM ".TABLE_PREFIX."posts p
3429              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
3430              LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid)
3431              WHERE p.pid IN ($pid_list) AND p.visible = '-1' AND t.firstpost != p.pid
3432          ");
3433          while($post = $db->fetch_array($query))
3434          {
3435              $pids[] = $post['pid'];
3436  
3437              if(!isset($thread_counters[$post['tid']]))
3438              {
3439                  $thread_counters[$post['tid']] = array(
3440                      'replies' => 0
3441                  );
3442              }
3443  
3444              ++$thread_counters[$post['tid']]['replies'];
3445  
3446              // If the thread of this post is deleted then we've already taken into account this counter as implied.
3447              // Updating it again would cause it to double count
3448              if($post['threadvisible'] == 1)
3449              {
3450                  if(!isset($forum_counters[$post['fid']]))
3451                  {
3452                      $forum_counters[$post['fid']] = array(
3453                          'num_posts' => 0
3454                      );
3455                  }
3456                  ++$forum_counters[$post['fid']]['num_posts'];
3457              }
3458  
3459              // If post counts enabled in this forum and the thread is approved, add 1
3460              if($post['usepostcounts'] != 0 && $post['threadvisible'] == 1)
3461              {
3462                  if(!isset($user_counters[$post['uid']]))
3463                  {
3464                      $user_counters[$post['uid']] = 0;
3465                  }
3466                  ++$user_counters[$post['uid']];
3467  
3468              }
3469          }
3470  
3471          if(empty($pids) && empty($threads_to_update))
3472          {
3473              return false;
3474          }
3475  
3476          if(!empty($pids))
3477          {
3478              $where = "pid IN (".implode(',', $pids).")";
3479              $db->update_query("posts", $update, $where);
3480          }
3481  
3482          $plugins->run_hooks("class_moderation_restore_posts", $pids);
3483  
3484          if(is_array($thread_counters))
3485          {
3486              foreach($thread_counters as $tid => $counters)
3487              {
3488                  $counters_update = array(
3489                      "deletedposts" => "-".$counters['replies'],
3490                      "replies" => "+".$counters['replies']
3491                  );
3492                  update_thread_counters($tid, $counters_update);
3493                  update_last_post($tid);
3494              }
3495          }
3496  
3497          if(is_array($forum_counters))
3498          {
3499              foreach($forum_counters as $fid => $counters)
3500              {
3501                  $updated_forum_stats = array(
3502                      'posts' => "+{$counters['num_posts']}",
3503                      'deletedposts' => "-{$counters['num_posts']}"
3504                  );
3505                  update_forum_counters($fid, $updated_forum_stats);
3506                  update_forum_lastpost($fid);
3507              }
3508          }
3509  
3510          if(!empty($user_counters))
3511          {
3512              foreach($user_counters as $uid => $counter)
3513              {
3514                  update_user_counters($uid, array('postnum' => "+{$counter}"));
3515              }
3516          }
3517  
3518          return true;
3519      }
3520  
3521      /**
3522       * Restore one or more threads
3523       *
3524       * @param array|int $tids Thread ID(s)
3525       * @return boolean true
3526       */
3527  	function restore_threads($tids)
3528      {
3529          global $db, $cache, $plugins;
3530  
3531          if(!is_array($tids))
3532          {
3533              $tids = array($tids);
3534          }
3535  
3536          if(empty($tids))
3537          {
3538              return false;
3539          }
3540  
3541          // Make sure we only have valid values
3542          $tids = array_map('intval', $tids);
3543  
3544          $tid_list = $forum_counters = $user_counters = $posts_to_restore = array();
3545  
3546          $tids_list = implode(",", $tids);
3547          $query = $db->simple_select("threads", "*", "tid IN ($tids_list)");
3548  
3549          while($thread = $db->fetch_array($query))
3550          {
3551              if($thread['visible'] != -1)
3552              {
3553                  continue;
3554              }
3555              $tid_list[] = $thread['tid'];
3556  
3557              $forum = get_forum($thread['fid']);
3558  
3559              if(!isset($forum_counters[$forum['fid']]))
3560              {
3561                  $forum_counters[$forum['fid']] = array(
3562                      'num_posts' => 0,
3563                      'num_threads' => 0,
3564                      'num_deleted_posts' => 0,
3565                      'num_unapproved_posts' => 0
3566                  );
3567              }
3568  
3569              if(!isset($user_counters[$thread['uid']]))
3570              {
3571                  $user_counters[$thread['uid']] = array(
3572                      'num_posts' => 0,
3573                      'num_threads' => 0
3574                  );
3575              }
3576  
3577              ++$forum_counters[$forum['fid']]['num_threads'];
3578              $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Remove implied visible from count
3579              $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['replies']+$thread['unapprovedposts']+1;
3580              $forum_counters[$forum['fid']]['num_unapproved_posts'] += $thread['unapprovedposts'];
3581  
3582              if($forum['usepostcounts'] != 0)
3583              {
3584                  // On approving thread restore user post counts
3585                  $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");
3586                  while($counter = $db->fetch_array($query2))
3587                  {
3588                      if(!isset($user_counters[$counter['uid']]))
3589                      {
3590                          $user_counters[$counter['uid']] = array(
3591                              'num_posts' => 0,
3592                              'num_threads' => 0
3593                          );
3594                      }
3595                      $user_counters[$counter['uid']]['num_posts'] += $counter['posts'];
3596                  }
3597              }
3598  
3599              if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|')
3600              {
3601                  ++$user_counters[$thread['uid']]['num_threads'];
3602              }
3603  
3604              $posts_to_restore[] = $thread['firstpost'];
3605          }
3606  
3607          if(!empty($tid_list))
3608          {
3609              $tid_moved_list = "";
3610              $comma = "";
3611              foreach($tid_list as $tid)
3612              {
3613                  $tid_moved_list .= "{$comma}'moved|{$tid}'";
3614                  $comma = ",";
3615              }
3616              $tid_list = implode(',', $tid_list);
3617              $update = array(
3618                  "visible" => 1
3619              );
3620              $db->update_query("threads", $update, "tid IN ($tid_list)");
3621              // Restore redirects, too
3622              $redirect_tids = array();
3623              $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})");
3624              while($redirect_tid = $db->fetch_field($query, 'tid'))
3625              {
3626                  $redirect_tids[] = $redirect_tid;
3627              }
3628              if(!empty($redirect_tids))
3629              {
3630                  $this->restore_threads($redirect_tids);
3631              }
3632              if(!empty($posts_to_restore))
3633              {
3634                  $db->update_query("posts", $update, "pid IN (".implode(',', $posts_to_restore).")");
3635              }
3636  
3637              $plugins->run_hooks("class_moderation_restore_threads", $tids);
3638  
3639              if(is_array($forum_counters))
3640              {
3641                  foreach($forum_counters as $fid => $counters)
3642                  {
3643                      // Update stats
3644                      $update_array = array(
3645                          "threads" => "+{$counters['num_threads']}",
3646                          "posts" => "+{$counters['num_posts']}",
3647                          "unapprovedposts" => "+{$counters['num_unapproved_posts']}",
3648                          "deletedposts" => "-{$counters['num_deleted_posts']}",
3649                          "deletedthreads" => "-{$counters['num_threads']}"
3650                      );
3651                      update_forum_counters($fid, $update_array);
3652                      update_forum_lastpost($fid);
3653                  }
3654              }
3655  
3656              if(!empty($user_counters))
3657              {
3658                  foreach($user_counters as $uid => $counters)
3659                  {
3660                      $update_array = array(
3661                          "postnum" => "+{$counters['num_posts']}",
3662                          "threadnum" => "+{$counters['num_threads']}",
3663                      );
3664                      update_user_counters($uid, $update_array);
3665                  }
3666              }
3667          }
3668          return true;
3669      }
3670  
3671      /**
3672       * Soft delete one or more threads
3673       *
3674       * @param array|int Thread ID(s)
3675       * @return boolean
3676       */
3677  	function soft_delete_threads($tids)
3678      {
3679          global $db, $cache, $plugins;
3680  
3681          if(!is_array($tids))
3682          {
3683              $tids = array($tids);
3684          }
3685  
3686          if(empty($tids))
3687          {
3688              return false;
3689          }
3690  
3691          // Make sure we only have valid values
3692          $tids = array_map('intval', $tids);
3693  
3694          $tid_list = implode(',', $tids);
3695          $tid_moved_list = "";
3696          $comma = "";
3697          foreach($tids as $tid)
3698          {
3699              $tid_moved_list .= "{$comma}'moved|{$tid}'";
3700              $comma = ",";
3701          }
3702  
3703          $forum_counters = $user_counters = $posts_to_delete = array();
3704  
3705          $tids_list = implode(",", $tids);
3706          $query = $db->simple_select("threads", "*", "tid IN ($tids_list)");
3707  
3708          while($thread = $db->fetch_array($query))
3709          {
3710              $forum = get_forum($thread['fid']);
3711  
3712              if($thread['visible'] == 1 || $thread['visible'] == 0)
3713              {
3714                  if(!isset($forum_counters[$forum['fid']]))
3715                  {
3716                      $forum_counters[$forum['fid']] = array(
3717                          'num_posts' => 0,
3718                          'num_threads' => 0,
3719                          'num_deleted_threads' => 0,
3720                          'num_deleted_posts' => 0,
3721                          'unapproved_threads' => 0,
3722                          'unapproved_posts' => 0
3723                      );
3724                  }
3725  
3726                  if(!isset($user_counters[$thread['uid']]))
3727                  {
3728                      $user_counters[$thread['uid']] = array(
3729                          'num_posts' => 0,
3730                          'num_threads' => 0
3731                      );
3732                  }
3733  
3734                  ++$forum_counters[$forum['fid']]['num_deleted_threads'];
3735                  $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['replies']+$thread['unapprovedposts']+1;
3736  
3737                  if($thread['visible'] == 1)
3738                  {
3739                      ++$forum_counters[$forum['fid']]['num_threads'];
3740                      $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Add implied invisible to count
3741                      $forum_counters[$forum['fid']]['unapproved_posts'] += $thread['unapprovedposts'];
3742                  }
3743                  else
3744                  {
3745                      ++$forum_counters[$forum['fid']]['unapproved_threads'];
3746                      $forum_counters[$forum['fid']]['unapproved_posts'] += $thread['replies']+$thread['deletedposts']+$thread['unapprovedposts']+1; // Add implied invisible to count
3747                      $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['deletedposts'];
3748                  }
3749  
3750                  // On unapproving thread update user post counts
3751                  if($thread['visible'] == 1 && $forum['usepostcounts'] != 0)
3752                  {
3753                      $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");
3754                      while($counter = $db->fetch_array($query2))
3755                      {
3756                          if(!isset($user_counters[$counter['uid']]))
3757                          {
3758                              $user_counters[$counter['uid']] = array(
3759                                  'num_posts' => 0,
3760                                  'num_threads' => 0
3761                              );
3762                          }
3763                          $user_counters[$counter['uid']]['num_posts'] += $counter['posts'];
3764                      }
3765                  }
3766  
3767                  if($thread['visible'] == 1 && $forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|')
3768                  {
3769                      ++$user_counters[$thread['uid']]['num_threads'];
3770                  }
3771              }
3772              $posts_to_delete[] = $thread['firstpost'];
3773          }
3774  
3775          $update = array(
3776              "visible" => -1
3777          );
3778          $db->update_query("threads", $update, "tid IN ($tid_list)");
3779          // Soft delete redirects, too
3780          $redirect_tids = array();
3781          $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})");
3782  
3783          mark_reports($tids, "threads");
3784  
3785          while($redirect_tid = $db->fetch_field($query, 'tid'))
3786          {
3787              $redirect_tids[] = $redirect_tid;
3788          }
3789          if(!empty($redirect_tids))
3790          {
3791              $this->soft_delete_threads($redirect_tids);
3792          }
3793          if(!empty($posts_to_delete))
3794          {
3795              $db->update_query("posts", $update, "pid IN (".implode(',', $posts_to_delete).")");
3796          }
3797  
3798          $plugins->run_hooks("class_moderation_soft_delete_threads", $tids);
3799  
3800          if(is_array($forum_counters))
3801          {
3802              foreach($forum_counters as $fid => $counters)
3803              {
3804                  // Update stats
3805                  $update_array = array(
3806                      "threads" => "-{$counters['num_threads']}",
3807                      "unapprovedthreads" => "-{$counters['unapproved_threads']}",
3808                      "posts" => "-{$counters['num_posts']}",
3809                      "unapprovedposts" => "-{$counters['unapproved_posts']}",
3810                      "deletedposts" => "+{$counters['num_deleted_posts']}",
3811                      "deletedthreads" => "+{$counters['num_deleted_threads']}"
3812                  );
3813                  update_forum_counters($fid, $update_array);
3814                  update_forum_lastpost($fid);
3815              }
3816          }
3817  
3818          if(!empty($user_counters))
3819          {
3820              foreach($user_counters as $uid => $counters)
3821              {
3822                  $update_array = array(
3823                      "postnum" => "-{$counters['num_posts']}",
3824                      "threadnum" => "-{$counters['num_threads']}",
3825                  );
3826                  update_user_counters($uid, $update_array);
3827              }
3828          }
3829  
3830          return true;
3831      }
3832  }


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