[ Index ] |
PHP Cross Reference of MyBB 1.8.38 |
[Summary view] [Print] [Text view]
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 // Disallow direct access to this file for security reasons 12 if(!defined("IN_MYBB")) 13 { 14 die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined."); 15 } 16 17 /* 18 EXAMPLE USE: 19 20 $post = get from POST data 21 $thread = get from DB using POST data id 22 23 $postHandler = new postDataHandler(); 24 if($postHandler->validate_post($post)) 25 { 26 $postHandler->insert_post($post); 27 } 28 29 */ 30 31 /** 32 * Post handling class, provides common structure to handle post data. 33 * 34 */ 35 class PostDataHandler extends DataHandler 36 { 37 /** 38 * The language file used in the data handler. 39 * 40 * @var string 41 */ 42 public $language_file = 'datahandler_post'; 43 44 /** 45 * The prefix for the language variables used in the data handler. 46 * 47 * @var string 48 */ 49 public $language_prefix = 'postdata'; 50 51 /** 52 * What are we performing? 53 * post = New post 54 * thread = New thread 55 * edit = Editing a thread or post 56 * 57 * @var string 58 */ 59 public $action; 60 61 /** 62 * Array of data inserted in to a post. 63 * 64 * @var array 65 */ 66 public $post_insert_data = array(); 67 68 /** 69 * Array of data used to update a post. 70 * 71 * @var array 72 */ 73 public $post_update_data = array(); 74 75 /** 76 * Post ID currently being manipulated by the datahandlers. 77 * 78 * @var int 79 */ 80 public $pid = 0; 81 82 /** 83 * Array of data inserted in to a thread. 84 * 85 * @var array 86 */ 87 public $thread_insert_data = array(); 88 89 /** 90 * Array of data used to update a thread. 91 * 92 * @var array 93 */ 94 public $thread_update_data = array(); 95 96 /** 97 * Thread ID currently being manipulated by the datahandlers. 98 * 99 * @var int 100 */ 101 public $tid = 0; 102 103 /** 104 * Values to be returned after inserting/updating a post/thread. 105 * 106 * @var array 107 */ 108 public $return_values = array(); 109 110 /** 111 * Is this the first post of a thread when editing 112 * 113 * @var boolean 114 */ 115 public $first_post = false; 116 117 /** 118 * Verifies the author of a post and fetches the username if necessary. 119 * 120 * @return boolean True if the author information is valid, false if invalid. 121 */ 122 function verify_author() 123 { 124 global $mybb, $lang; 125 126 $post = &$this->data; 127 128 // Don't have a user ID at all - not good (note, a user id of 0 will still work). 129 if(!isset($post['uid'])) 130 { 131 $this->set_error("invalid_user_id"); 132 return false; 133 } 134 // If we have a user id but no username then fetch the username. 135 else if($post['uid'] > 0 && empty($post['username'])) 136 { 137 $user = get_user($post['uid']); 138 $post['username'] = $user['username']; 139 } 140 // if the uid is 0 verify the username 141 else if($post['uid'] == 0 && $post['username'] != '') 142 { 143 // Set up user handler 144 require_once MYBB_ROOT."inc/datahandlers/user.php"; 145 $userhandler = new UserDataHandler(); 146 147 $data_array = array('username' => $post['username']); 148 $userhandler->set_data($data_array); 149 150 if(!$userhandler->verify_username()) 151 { 152 // invalid username 153 $this->errors = array_merge($this->errors, $userhandler->get_errors()); 154 return false; 155 } 156 157 if($userhandler->verify_username_exists()) 158 { 159 // username is in use 160 $this->errors = array_merge($this->errors, $userhandler->get_errors()); 161 return false; 162 } 163 } 164 165 return true; 166 } 167 168 /** 169 * Verifies a post subject. 170 * 171 * @return boolean True when valid, false when not valid. 172 */ 173 function verify_subject() 174 { 175 global $db; 176 $post = &$this->data; 177 $subject = &$post['subject']; 178 $subject = trim_blank_chrs($subject); 179 180 if($this->method == "update" && $post['pid']) 181 { 182 // If this is the first post there needs to be a subject, else make it the default one. 183 if(my_strlen($subject) == 0 && $this->first_post) 184 { 185 $this->set_error("firstpost_no_subject"); 186 return false; 187 } 188 elseif(my_strlen($subject) == 0) 189 { 190 $thread = get_thread($post['tid']); 191 $subject = "RE: ".$thread['subject']; 192 } 193 } 194 195 // This is a new post 196 else if($this->action == "post") 197 { 198 if(my_strlen($subject) == 0) 199 { 200 $thread = get_thread($post['tid']); 201 $subject = "RE: ".$thread['subject']; 202 } 203 } 204 205 // This is a new thread and we require that a subject is present. 206 else 207 { 208 if(my_strlen($subject) == 0) 209 { 210 $this->set_error("missing_subject"); 211 return false; 212 } 213 } 214 215 // If post is reply and begins with "RE: ", remove 4 from subject length. 216 $subject_length = my_strlen($subject); 217 if($this->action == "post") 218 { 219 $position_re = my_strpos($subject, "RE: "); 220 if($position_re !== false && $position_re == 0) 221 { 222 $subject_length = $subject_length - 4; 223 } 224 } 225 226 if($subject_length > 85) 227 { 228 // Subject is too long 229 $this->set_error('subject_too_long', my_strlen($subject)); 230 return false; 231 } 232 233 // Subject is valid - return true. 234 return true; 235 } 236 237 /** 238 * Verifies a post message. 239 * 240 * @return bool 241 */ 242 function verify_message() 243 { 244 global $db, $mybb; 245 246 $post = &$this->data; 247 $post['message'] = trim_blank_chrs($post['message']); 248 249 // Do we even have a message at all? 250 if(my_strlen($post['message']) == 0) 251 { 252 $this->set_error("missing_message"); 253 return false; 254 } 255 else 256 { 257 $limit = (int)$mybb->settings['maxmessagelength']; 258 $dblimit = 0; 259 260 // If database is mysql or mysqli check field type and set max database limit 261 if(stripos($db->type, 'my') !== false) 262 { 263 $fields = $db->show_fields_from("posts"); 264 $type = $fields[array_search('message', array_column($fields, 'Field'))]['Type']; 265 switch(strtolower($type)) 266 { 267 case 'longtext': 268 $dblimit = 4294967295; 269 break; 270 case 'mediumtext': 271 $dblimit = 16777215; 272 break; 273 case 'text': 274 default: 275 $dblimit = 65535; 276 break; 277 } 278 } 279 280 if($limit > 0 || $dblimit > 0) 281 { 282 if(isset($post['fid'])) 283 { 284 $fid = $post['fid']; 285 } 286 else 287 { 288 $fid = 0; 289 } 290 if(isset($post['uid'])) 291 { 292 $uid = $post['uid']; 293 } 294 else 295 { 296 $uid = 0; 297 } 298 299 $is_moderator = is_moderator($fid, "", $uid); 300 // Consider minimum in user defined and database limit other than 0 301 if($limit > 0 && $dblimit > 0) 302 { 303 $limit = $is_moderator ? $dblimit : min($limit, $dblimit); 304 } 305 else 306 { 307 $limit = max($limit, $dblimit); 308 } 309 310 if(strlen($post['message']) > $limit && (!$is_moderator || $limit == $dblimit)) 311 { 312 $this->set_error("message_too_long", array($limit, strlen($post['message']))); 313 return false; 314 } 315 } 316 317 if(!isset($post['fid'])) 318 { 319 $post['fid'] = 0; 320 } 321 322 if(!$mybb->settings['mycodemessagelength']) 323 { 324 // Check to see of the text is full of MyCode 325 require_once MYBB_ROOT."inc/class_parser.php"; 326 $parser = new postParser; 327 328 $message = $parser->text_parse_message($post['message']); 329 330 if(my_strlen($message) < $mybb->settings['minmessagelength'] && $mybb->settings['minmessagelength'] > 0 && !is_moderator($post['fid'], "", $post['uid'])) 331 { 332 $this->set_error("message_too_short", array($mybb->settings['minmessagelength'])); 333 return false; 334 } 335 } 336 else if(my_strlen($post['message']) < $mybb->settings['minmessagelength'] && $mybb->settings['minmessagelength'] > 0 && !is_moderator($post['fid'], "", $post['uid'])) 337 { 338 $this->set_error("message_too_short", array($mybb->settings['minmessagelength'])); 339 return false; 340 } 341 } 342 return true; 343 } 344 345 /** 346 * Verifies the specified post options are correct. 347 * 348 * @return boolean True 349 */ 350 function verify_options() 351 { 352 $options = &$this->data['options']; 353 354 // Verify yes/no options. 355 $this->verify_yesno_option($options, 'signature', 0); 356 $this->verify_yesno_option($options, 'disablesmilies', 0); 357 358 return true; 359 } 360 361 /** 362 * Verify that the user is not flooding the system. 363 * 364 * @return boolean 365 */ 366 function verify_post_flooding() 367 { 368 global $mybb; 369 370 $post = &$this->data; 371 372 // Check if post flooding is enabled within MyBB or if the admin override option is specified. 373 if($mybb->settings['postfloodcheck'] == 1 && $post['uid'] != 0 && $this->admin_override == false) 374 { 375 if($this->verify_post_merge(true) !== true) 376 { 377 return true; 378 } 379 380 // Fetch the user information for this post - used to check their last post date. 381 $user = get_user($post['uid']); 382 383 // A little bit of calculation magic and moderator status checking. 384 if(TIME_NOW-$user['lastpost'] <= $mybb->settings['postfloodsecs'] && !is_moderator($post['fid'], "", $user['uid'])) 385 { 386 // Oops, user has been flooding - throw back error message. 387 $time_to_wait = ($mybb->settings['postfloodsecs'] - (TIME_NOW-$user['lastpost'])) + 1; 388 if($time_to_wait == 1) 389 { 390 $this->set_error("post_flooding_one_second"); 391 } 392 else 393 { 394 $this->set_error("post_flooding", array($time_to_wait)); 395 } 396 return false; 397 } 398 } 399 // All is well that ends well - return true. 400 return true; 401 } 402 403 /** 404 * @param bool $simple_mode 405 * 406 * @return array|bool 407 */ 408 function verify_post_merge($simple_mode=false) 409 { 410 global $mybb, $db, $session; 411 412 $post = &$this->data; 413 414 // Are we starting a new thread? 415 if(empty($post['tid'])) 416 { 417 return true; 418 } 419 420 // Are we even turned on? 421 if(empty($mybb->settings['postmergemins'])) 422 { 423 return true; 424 } 425 426 // Assign a default separator if none is specified 427 if(trim($mybb->settings['postmergesep']) == "") 428 { 429 $mybb->settings['postmergesep'] = "[hr]"; 430 } 431 432 // Check to see if this person is in a usergroup that is excluded 433 if(is_member($mybb->settings['postmergeuignore'], $post['uid'])) 434 { 435 return true; 436 } 437 438 // Select the lastpost and fid information for this thread 439 $query = $db->simple_select("threads", "lastpost,fid", "lastposteruid='".$post['uid']."' AND tid='".$post['tid']."'", array('limit' => '1')); 440 $thread = $db->fetch_array($query); 441 442 // Check to see if the same author has posted within the merge post time limit 443 if( 444 !$thread || ( 445 ((int)$mybb->settings['postmergemins'] != 0 && trim($mybb->settings['postmergemins']) != "") && 446 (TIME_NOW-$thread['lastpost']) > ((int)$mybb->settings['postmergemins']*60) 447 ) 448 ) 449 { 450 return true; 451 } 452 453 if($mybb->settings['postmergefignore'] == -1) 454 { 455 return true; 456 } 457 elseif($mybb->settings['postmergefignore'] != '') 458 { 459 $fids = explode(',', (string)$mybb->settings['postmergefignore']); 460 461 if(is_array($fids)) 462 { 463 foreach($fids as &$fid) 464 { 465 $fid = (int)$fid; 466 } 467 unset($fid); 468 469 if(in_array($thread['fid'], $fids)) 470 { 471 return true; 472 } 473 } 474 } 475 476 if($simple_mode == true) 477 { 478 return false; 479 } 480 481 if(!empty($post['uid'])) 482 { 483 $user_check = "uid='".$post['uid']."'"; 484 } 485 else 486 { 487 $user_check = "ipaddress=".$db->escape_binary($session->packedip); 488 } 489 490 $query = $db->simple_select("posts", "pid,message,visible", "{$user_check} AND tid='".$post['tid']."' AND dateline='".$thread['lastpost']."'", array('order_by' => 'pid', 'order_dir' => 'DESC', 'limit' => 1)); 491 return $db->fetch_array($query); 492 } 493 494 /** 495 * Verifies the image count. 496 * 497 * @return boolean True when valid, false when not valid. 498 */ 499 function verify_image_count() 500 { 501 global $mybb, $db; 502 503 $post = &$this->data; 504 505 if(isset($post['uid'])) 506 { 507 $uid = $post['uid']; 508 } 509 else 510 { 511 $uid = null; 512 } 513 514 // Get the permissions of the user who is making this post or thread 515 $permissions = user_permissions($uid); 516 517 // Fetch the forum this post is being made in 518 if(empty($post['fid'])) 519 { 520 $query = $db->simple_select('posts', 'fid', "pid = '{$post['pid']}'"); 521 $post['fid'] = $db->fetch_field($query, 'fid'); 522 } 523 $forum = get_forum($post['fid']); 524 525 // Check if this post contains more images than the forum allows 526 if((!isset($post['savedraft']) || $post['savedraft'] != 1) && $mybb->settings['maxpostimages'] != 0 && $permissions['cancp'] != 1) 527 { 528 require_once MYBB_ROOT."inc/class_parser.php"; 529 $parser = new postParser; 530 531 // Parse the message. 532 $parser_options = array( 533 "allow_html" => $forum['allowhtml'], 534 "allow_mycode" => $forum['allowmycode'], 535 "allow_imgcode" => $forum['allowimgcode'], 536 "allow_videocode" => $forum['allowvideocode'], 537 "filter_badwords" => 1 538 ); 539 540 if(empty($post['options']['disablesmilies'])) 541 { 542 $parser_options['allow_smilies'] = $forum['allowsmilies']; 543 } 544 else 545 { 546 $parser_options['allow_smilies'] = 0; 547 } 548 549 $image_check = $parser->parse_message($post['message'], $parser_options); 550 551 // And count the number of image tags in the message. 552 $image_count = substr_count($image_check, "<img"); 553 if($image_count > $mybb->settings['maxpostimages']) 554 { 555 // Throw back a message if over the count with the number of images as well as the maximum number of images per post. 556 $this->set_error("too_many_images", array(1 => $image_count, 2 => $mybb->settings['maxpostimages'])); 557 return false; 558 } 559 } 560 561 return true; 562 } 563 564 /** 565 * Verifies the video count. 566 * 567 * @return boolean True when valid, false when not valid. 568 */ 569 function verify_video_count() 570 { 571 global $mybb, $db; 572 573 $post = &$this->data; 574 575 if(isset($post['uid'])) 576 { 577 $uid = $post['uid']; 578 } 579 else 580 { 581 $uid = null; 582 } 583 584 // Get the permissions of the user who is making this post or thread 585 $permissions = user_permissions($uid); 586 587 // Check if this post contains more videos than the forum allows 588 if((!isset($post['savedraft']) || $post['savedraft'] != 1) && $mybb->settings['maxpostvideos'] != 0 && $permissions['cancp'] != 1) 589 { 590 // And count the number of video tags in the message. 591 $video_count = substr_count($post['message'], "[video="); 592 if($video_count > $mybb->settings['maxpostvideos']) 593 { 594 // Throw back a message if over the count with the number of images as well as the maximum number of images per post. 595 $this->set_error("too_many_videos", array(1 => $video_count, 2 => $mybb->settings['maxpostvideos'])); 596 return false; 597 } 598 } 599 600 return true; 601 } 602 603 /** 604 * Verify the reply-to post. 605 * 606 * @return boolean True when valid, false when not valid. 607 */ 608 function verify_reply_to() 609 { 610 global $db; 611 $post = &$this->data; 612 613 // Check if the post being replied to actually exists in this thread. 614 if($post['replyto']) 615 { 616 $query = $db->simple_select("posts", "pid", "pid='".(int)$post['replyto']."'"); 617 $valid_post = $db->fetch_array($query); 618 if(!$valid_post['pid']) 619 { 620 $post['replyto'] = 0; 621 } 622 else 623 { 624 return true; 625 } 626 } 627 628 // If this post isn't a reply to a specific post, attach it to the first post. 629 if(!$post['replyto']) 630 { 631 $options = array( 632 "limit_start" => 0, 633 "limit" => 1, 634 "order_by" => "dateline, pid", 635 ); 636 $query = $db->simple_select("posts", "pid", "tid='{$post['tid']}'", $options); 637 $reply_to = $db->fetch_array($query); 638 $post['replyto'] = $reply_to['pid']; 639 } 640 641 return true; 642 } 643 644 /** 645 * Verify the post icon. 646 * 647 * @return boolean True when valid, false when not valid. 648 */ 649 function verify_post_icon() 650 { 651 global $cache; 652 653 $post = &$this->data; 654 655 $posticons_cache = $cache->read("posticons"); 656 657 // If we don't have a post icon assign it as 0. 658 if(empty($post['icon']) || !isset($posticons_cache[$post['icon']])) 659 { 660 $post['icon'] = 0; 661 } 662 return true; 663 } 664 665 /** 666 * Verify the dateline. 667 * 668 * @return boolean True when valid, false when not valid. 669 */ 670 function verify_dateline() 671 { 672 $dateline = &$this->data['dateline']; 673 674 // The date has to be numeric and > 0. 675 if($dateline < 0 || is_numeric($dateline) == false) 676 { 677 $dateline = TIME_NOW; 678 } 679 } 680 681 /** 682 * Verify thread prefix. 683 * 684 * @return boolean True when valid, false when not valid. 685 */ 686 function verify_prefix() 687 { 688 $prefix = &$this->data['prefix']; 689 690 // If a valid prefix isn't supplied, don't assign one. 691 if(empty($prefix)) 692 { 693 $prefix = 0; 694 } 695 else 696 { 697 if(!empty($this->data['tid'])) 698 { 699 // Fetch the thread 700 $thread = get_thread($this->data['tid']); 701 } 702 703 $prefix_cache = build_prefixes($prefix); 704 705 if(empty($prefix_cache)) 706 { 707 $this->set_error('invalid_prefix'); 708 return false; 709 } 710 if($prefix_cache['groups'] != "-1") 711 { 712 if(!empty($this->data['edit_uid'])) 713 { 714 // Post is being edited 715 $user = get_user($this->data['edit_uid']); 716 } 717 else 718 { 719 $user = get_user($this->data['uid']); 720 } 721 722 if(!is_member($prefix_cache['groups'], array('usergroup' => $user['usergroup'], 'additionalgroups' => $user['additionalgroups'])) && (empty($this->data['tid']) || $prefix != $thread['prefix'])) 723 { 724 $this->set_error('invalid_prefix'); 725 return false; 726 } 727 } 728 if($prefix_cache['forums'] != "-1") 729 { 730 // Decide whether this prefix can be used in our forum 731 $forums = explode(",", $prefix_cache['forums']); 732 733 if(!in_array($this->data['fid'], $forums) && (empty($this->data['tid']) || $prefix != $thread['prefix'])) 734 { 735 $this->set_error('invalid_prefix'); 736 return false; 737 } 738 } 739 } 740 741 // Does this forum require a prefix? 742 $forum = get_forum($this->data['fid']); 743 744 if($forum['requireprefix'] == 1) 745 { 746 $num_prefixes = false; 747 748 // Go through each of our prefixes and decide if there are any possible prefixes to use. 749 if(!empty($this->data['edit_uid'])) 750 { 751 // Post is being edited 752 $user = get_user($this->data['edit_uid']); 753 } 754 else 755 { 756 $user = get_user($this->data['uid']); 757 } 758 759 $prefix_cache = build_prefixes(); 760 761 if(!empty($prefix_cache)) 762 { 763 foreach($prefix_cache as $required) 764 { 765 if($required['forums'] != "-1") 766 { 767 // Decide whether this prefix can be used in our forum 768 $forums = explode(",", $required['forums']); 769 770 if(!in_array($forum['fid'], $forums)) 771 { 772 continue; 773 } 774 } 775 776 if(is_member($required['groups'], array('usergroup' => $user['usergroup'], 'additionalgroups' => $user['additionalgroups']))) 777 { 778 $num_prefixes = true; 779 } 780 } 781 } 782 783 if($prefix == 0 && $num_prefixes) 784 { 785 $this->set_error('require_prefix'); 786 return false; 787 } 788 } 789 790 return true; 791 } 792 793 /** 794 * Validate a post. 795 * 796 * @return boolean True when valid, false when invalid. 797 */ 798 function validate_post() 799 { 800 global $mybb, $db, $plugins; 801 802 $post = &$this->data; 803 $time = TIME_NOW; 804 805 $this->action = "post"; 806 807 if($this->method != "update" && !$post['savedraft']) 808 { 809 $this->verify_post_flooding(); 810 } 811 812 // Are we editing an existing thread or post? 813 if($this->method == "update") 814 { 815 if(empty($post['tid'])) 816 { 817 $query = $db->simple_select("posts", "tid", "pid='".(int)$post['pid']."'"); 818 $post['tid'] = $db->fetch_field($query, "tid"); 819 } 820 // Here we determine if we're editing the first post of a thread or not. 821 $options = array( 822 "limit" => 1, 823 "limit_start" => 0, 824 "order_by" => "dateline, pid", 825 ); 826 $query = $db->simple_select("posts", "pid", "tid='".$post['tid']."'", $options); 827 $first_check = $db->fetch_array($query); 828 if($first_check['pid'] == $post['pid']) 829 { 830 $this->first_post = true; 831 } 832 } 833 834 // Verify all post assets. 835 836 if($this->method == "insert" || array_key_exists('uid', $post)) 837 { 838 $this->verify_author(); 839 } 840 841 if($this->method == "insert" || array_key_exists('subject', $post)) 842 { 843 $this->verify_subject(); 844 } 845 846 if($this->method == "insert" || array_key_exists('message', $post)) 847 { 848 $this->verify_message(); 849 $this->verify_image_count(); 850 $this->verify_video_count(); 851 } 852 853 if($this->method == "insert" || array_key_exists('dateline', $post)) 854 { 855 $this->verify_dateline(); 856 } 857 858 if($this->method == "insert" || array_key_exists('replyto', $post)) 859 { 860 $this->verify_reply_to(); 861 } 862 863 if($this->method == "insert" || array_key_exists('icon', $post)) 864 { 865 $this->verify_post_icon(); 866 } 867 868 if($this->method == "insert" || array_key_exists('options', $post)) 869 { 870 $this->verify_options(); 871 } 872 873 if($this->method == "update" && $this->first_post) 874 { 875 $this->verify_prefix(); 876 } 877 878 $plugins->run_hooks("datahandler_post_validate_post", $this); 879 880 // We are done validating, return. 881 $this->set_validated(true); 882 if(count($this->get_errors()) > 0) 883 { 884 return false; 885 } 886 else 887 { 888 return true; 889 } 890 } 891 892 /** 893 * Insert a post into the database. 894 * 895 * @return array Array of new post details, pid and visibility. 896 */ 897 function insert_post() 898 { 899 global $db, $mybb, $plugins, $cache, $lang; 900 901 $post = &$this->data; 902 903 // Yes, validating is required. 904 if(!$this->get_validated()) 905 { 906 die("The post needs to be validated before inserting it into the DB."); 907 } 908 if(count($this->get_errors()) > 0) 909 { 910 die("The post is not valid."); 911 } 912 913 // Fetch the thread 914 $thread = get_thread($post['tid']); 915 916 $closed = $thread['closed']; 917 918 // This post is being saved as a draft. 919 if($post['savedraft']) 920 { 921 $visible = -2; 922 } 923 924 // Otherwise this post is being made now and we have a bit to do. 925 else 926 { 927 // Automatic subscription to the thread 928 if($post['uid'] > 0) 929 { 930 require_once MYBB_ROOT."inc/functions_user.php"; 931 if($post['options']['subscriptionmethod'] == "") 932 { 933 remove_subscribed_thread($post['tid'], $post['uid']); 934 } 935 else 936 { 937 switch($post['options']['subscriptionmethod']) 938 { 939 case "pm": 940 $notification = 2; 941 break; 942 case "email": 943 $notification = 1; 944 break; 945 default: 946 $notification = 0; 947 } 948 add_subscribed_thread($post['tid'], $notification, $post['uid']); 949 } 950 } 951 952 // Perform any selected moderation tools. 953 $ismod = is_moderator($post['fid'], "", $post['uid']); 954 if($ismod && isset($post['modoptions'])) 955 { 956 $lang->load($this->language_file, true); 957 958 $modoptions = $post['modoptions']; 959 $modlogdata['fid'] = $thread['fid']; 960 $modlogdata['tid'] = $thread['tid']; 961 962 $modoptions_update = array(); 963 964 // Close the thread. 965 if(!empty($modoptions['closethread']) && $thread['closed'] != 1 && is_moderator($post['fid'], "canopenclosethreads", $post['uid'])) 966 { 967 $modoptions_update['closed'] = $closed = 1; 968 log_moderator_action($modlogdata, $lang->thread_closed); 969 } 970 971 // Open the thread. 972 if(empty($modoptions['closethread']) && $thread['closed'] == 1 && is_moderator($post['fid'], "canopenclosethreads", $post['uid'])) 973 { 974 $modoptions_update['closed'] = $closed = 0; 975 log_moderator_action($modlogdata, $lang->thread_opened); 976 } 977 978 // Stick the thread. 979 if(!empty($modoptions['stickthread']) && $thread['sticky'] != 1 && is_moderator($post['fid'], "canstickunstickthreads", $post['uid'])) 980 { 981 $modoptions_update['sticky'] = 1; 982 log_moderator_action($modlogdata, $lang->thread_stuck); 983 } 984 985 // Unstick the thread. 986 if(empty($modoptions['stickthread']) && $thread['sticky'] == 1 && is_moderator($post['fid'], "canstickunstickthreads", $post['uid'])) 987 { 988 $modoptions_update['sticky'] = 0; 989 log_moderator_action($modlogdata, $lang->thread_unstuck); 990 } 991 992 // Execute moderation options. 993 if($modoptions_update) 994 { 995 $db->update_query('threads', $modoptions_update, "tid='{$thread['tid']}'"); 996 } 997 } 998 999 // Fetch the forum this post is being made in 1000 $forum = get_forum($post['fid']); 1001 1002 // Decide on the visibility of this post. 1003 $forumpermissions = forum_permissions($post['fid'], $post['uid']); 1004 if($forumpermissions['modposts'] == 1 && !$ismod) 1005 { 1006 $visible = 0; 1007 } 1008 else 1009 { 1010 $visible = 1; 1011 } 1012 1013 // Are posts from this user being moderated? Change visibility 1014 if($mybb->user['uid'] == $post['uid'] && $mybb->user['moderateposts'] == 1) 1015 { 1016 $visible = 0; 1017 } 1018 } 1019 1020 if(!isset($post['pid'])) 1021 { 1022 $post['pid'] = 0; 1023 } 1024 1025 $post['pid'] = (int)$post['pid']; 1026 $post['uid'] = (int)$post['uid']; 1027 1028 if($post['pid'] > 0) 1029 { 1030 $query = $db->simple_select("posts", "tid", "pid='{$post['pid']}' AND uid='{$post['uid']}' AND visible='-2'"); 1031 $draft_check = $db->fetch_field($query, "tid"); 1032 } 1033 else 1034 { 1035 $draft_check = false; 1036 } 1037 1038 if($this->method != "update" && $visible == 1) 1039 { 1040 $double_post = $this->verify_post_merge(); 1041 1042 // Only combine if they are both invisible (mod queue'd forum) or both visible 1043 if($double_post !== true && $double_post['visible'] == $visible) 1044 { 1045 $_message = $post['message']; 1046 1047 $post['message'] = $double_post['message'] .= "\n".$mybb->settings['postmergesep']."\n".$post['message']; 1048 1049 if ($this->validate_post()) 1050 { 1051 $this->pid = $double_post['pid']; 1052 1053 $update_query = array( 1054 "message" => $db->escape_string($double_post['message']) 1055 ); 1056 $update_query['edituid'] = (int)$post['uid']; 1057 $update_query['edittime'] = TIME_NOW; 1058 $db->update_query("posts", $update_query, "pid='".$double_post['pid']."'"); 1059 1060 if($draft_check) 1061 { 1062 $db->delete_query("posts", "pid='".$post['pid']."'"); 1063 } 1064 1065 if($post['posthash']) 1066 { 1067 // Assign any uploaded attachments with the specific posthash to the merged post. 1068 $post['posthash'] = $db->escape_string($post['posthash']); 1069 1070 $query = $db->simple_select("attachments", "COUNT(aid) AS attachmentcount", "pid='0' AND visible='1' AND posthash='{$post['posthash']}'"); 1071 $attachmentcount = $db->fetch_field($query, "attachmentcount"); 1072 1073 if($attachmentcount > 0) 1074 { 1075 // Update forum count 1076 update_thread_counters($post['tid'], array('attachmentcount' => "+{$attachmentcount}")); 1077 } 1078 1079 $attachmentassign = array( 1080 "pid" => $double_post['pid'], 1081 "posthash" => '' 1082 ); 1083 $db->update_query("attachments", $attachmentassign, "posthash='{$post['posthash']}' AND pid='0'"); 1084 } 1085 1086 // Return the post's pid and whether or not it is visible. 1087 $this->return_values = array( 1088 "pid" => $double_post['pid'], 1089 "visible" => $visible, 1090 "merge" => true 1091 ); 1092 1093 $plugins->run_hooks("datahandler_post_insert_merge", $this); 1094 1095 return $this->return_values; 1096 } 1097 else 1098 { 1099 $post['message'] = $_message; 1100 } 1101 } 1102 } 1103 1104 if($visible == 1) 1105 { 1106 $now = TIME_NOW; 1107 1108 // Yes, the value to the lastpost key in this array has single quotes within double quotes. It's not a bug. 1109 $update_array = array( 1110 'lastpost' => "'{$now}'" 1111 ); 1112 if($forum['usepostcounts'] != 0 && $thread['visible'] == 1) 1113 { 1114 $update_array['postnum'] = 'postnum+1'; 1115 } 1116 1117 $db->update_query("users", $update_array, "uid='{$post['uid']}'", 1, true); 1118 } 1119 1120 // Are we updating a post which is already a draft? Perhaps changing it into a visible post? 1121 if($draft_check) 1122 { 1123 // Update a post that is a draft 1124 $this->post_update_data = array( 1125 "subject" => $db->escape_string($post['subject']), 1126 "icon" => (int)$post['icon'], 1127 "uid" => $post['uid'], 1128 "username" => $db->escape_string($post['username']), 1129 "dateline" => (int)$post['dateline'], 1130 "message" => $db->escape_string($post['message']), 1131 "ipaddress" => $db->escape_binary($post['ipaddress']), 1132 "includesig" => $post['options']['signature'], 1133 "smilieoff" => $post['options']['disablesmilies'], 1134 "visible" => $visible 1135 ); 1136 1137 $plugins->run_hooks("datahandler_post_insert_post", $this); 1138 1139 $db->update_query("posts", $this->post_update_data, "pid='{$post['pid']}'"); 1140 $this->pid = $post['pid']; 1141 } 1142 else 1143 { 1144 // Insert the post. 1145 $this->post_insert_data = array( 1146 "tid" => (int)$post['tid'], 1147 "replyto" => (int)$post['replyto'], 1148 "fid" => (int)$post['fid'], 1149 "subject" => $db->escape_string($post['subject']), 1150 "icon" => (int)$post['icon'], 1151 "uid" => $post['uid'], 1152 "username" => $db->escape_string($post['username']), 1153 "dateline" => $post['dateline'], 1154 "message" => $db->escape_string($post['message']), 1155 "ipaddress" => $db->escape_binary($post['ipaddress']), 1156 "includesig" => $post['options']['signature'], 1157 "smilieoff" => $post['options']['disablesmilies'], 1158 "visible" => $visible 1159 ); 1160 1161 $plugins->run_hooks("datahandler_post_insert_post", $this); 1162 1163 $this->pid = $db->insert_query("posts", $this->post_insert_data); 1164 } 1165 1166 // Assign any uploaded attachments with the specific posthash to the newly created post. 1167 if($post['posthash']) 1168 { 1169 $post['posthash'] = $db->escape_string($post['posthash']); 1170 $attachmentassign = array( 1171 "pid" => $this->pid, 1172 "posthash" => '' 1173 ); 1174 $db->update_query("attachments", $attachmentassign, "posthash='{$post['posthash']}' AND pid='0'"); 1175 } 1176 1177 $thread_update = array(); 1178 if($visible == 1 && $thread['visible'] == 1) 1179 { 1180 require_once MYBB_ROOT.'inc/class_parser.php'; 1181 $parser = new Postparser; 1182 1183 $done_users = array(); 1184 1185 $subject = $parser->parse_badwords($thread['subject']); 1186 1187 $parser_options = array( 1188 'me_username' => $post['username'], 1189 'filter_badwords' => 1 1190 ); 1191 1192 $excerpt = $parser->text_parse_message($post['message'], $parser_options); 1193 $excerpt = my_substr($excerpt, 0, $mybb->settings['subscribeexcerpt']).$lang->emailbit_viewthread; 1194 1195 // Fetch any users subscribed to this thread receiving instant notification and queue up their subscription notices 1196 $query = $db->query(" 1197 SELECT u.username, u.email, u.uid, u.language, u.loginkey, u.salt, u.regdate, s.notification 1198 FROM ".TABLE_PREFIX."threadsubscriptions s 1199 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=s.uid) 1200 WHERE (s.notification='1' OR s.notification='2') AND s.tid='{$post['tid']}' 1201 AND s.uid != '{$post['uid']}' 1202 AND u.lastactive>'{$thread['lastpost']}' 1203 "); 1204 1205 $args = array( 1206 'this' => &$this, 1207 'done_users' => &$done_users, 1208 'users' => array() 1209 ); 1210 1211 while($subscribedmember = $db->fetch_array($query)) 1212 { 1213 if(isset($done_users[$subscribedmember['uid']])) 1214 { 1215 continue; 1216 } 1217 1218 $args['users'][$subscribedmember['uid']] = (int)$subscribedmember['uid']; 1219 1220 $done_users[$subscribedmember['uid']] = 1; 1221 1222 $forumpermissions = forum_permissions($thread['fid'], $subscribedmember['uid']); 1223 if($forumpermissions['canview'] == 0 || $forumpermissions['canviewthreads'] == 0) 1224 { 1225 continue; 1226 } 1227 1228 if($thread['uid'] != $subscribedmember['uid'] && $forumpermissions['canonlyviewownthreads'] == 1 && !is_moderator($thread['fid'], "", $subscribedmember['uid'])) 1229 { 1230 // User isn't a moderator or the author of the thread... 1231 continue; 1232 } 1233 1234 if($subscribedmember['language'] != '' && $lang->language_exists($subscribedmember['language'])) 1235 { 1236 $uselang = $subscribedmember['language']; 1237 } 1238 elseif($mybb->settings['orig_bblanguage']) 1239 { 1240 $uselang = $mybb->settings['orig_bblanguage']; 1241 } 1242 else 1243 { 1244 $uselang = "english"; 1245 } 1246 1247 if($uselang == $mybb->settings['bblanguage']) 1248 { 1249 if($subscribedmember['notification'] == 1) 1250 { 1251 $emailsubject = $lang->emailsubject_subscription; 1252 $emailmessage = $lang->email_subscription; 1253 } 1254 1255 // If the poster is unregistered and hasn't set a username, call them Guest 1256 if(!$post['uid'] && !$post['username']) 1257 { 1258 $post['username'] = htmlspecialchars_uni($lang->guest); 1259 } 1260 } 1261 else 1262 { 1263 1264 if(($subscribedmember['notification'] == 1 && !isset($langcache[$uselang]['emailsubject_subscription'])) || !isset($langcache[$uselang]['guest'])) 1265 { 1266 $userlang = new MyLanguage; 1267 $userlang->set_path(MYBB_ROOT."inc/languages"); 1268 $userlang->set_language($uselang); 1269 if($subscribedmember['notification'] == 1) 1270 { 1271 $userlang->load("messages"); 1272 $langcache[$uselang]['emailsubject_subscription'] = $userlang->emailsubject_subscription; 1273 $langcache[$uselang]['email_subscription'] = $userlang->email_subscription; 1274 } 1275 $userlang->load("global"); 1276 1277 $langcache[$uselang]['guest'] = $userlang->guest; 1278 unset($userlang); 1279 } 1280 if($subscribedmember['notification'] == 1) 1281 { 1282 $emailsubject = $langcache[$uselang]['emailsubject_subscription']; 1283 $emailmessage = $langcache[$uselang]['email_subscription']; 1284 } 1285 1286 // If the poster is unregistered and hasn't set a username, call them Guest 1287 if(!$post['uid'] && !$post['username']) 1288 { 1289 $post['username'] = $langcache[$uselang]['guest']; 1290 } 1291 } 1292 1293 if($subscribedmember['notification'] == 1) 1294 { 1295 $emailsubject = $lang->sprintf($emailsubject, $subject); 1296 1297 $emailmessage = $lang->sprintf($emailmessage, $subscribedmember['username'], $post['username'], $mybb->settings['bbname'], $subject, $excerpt, $mybb->settings['bburl'], str_replace("&", "&", get_thread_link($thread['tid'], 0, "newpost")), $thread['tid']); 1298 $new_email = array( 1299 "mailto" => $db->escape_string($subscribedmember['email']), 1300 "mailfrom" => '', 1301 "subject" => $db->escape_string($emailsubject), 1302 "message" => $db->escape_string($emailmessage), 1303 "headers" => '' 1304 ); 1305 $db->insert_query("mailqueue", $new_email); 1306 unset($userlang); 1307 $queued_email = 1; 1308 } 1309 elseif($subscribedmember['notification'] == 2) 1310 { 1311 $pm = array( 1312 'subject' => array('pmsubject_subscription', $subject), 1313 'message' => array('pm_subscription', $subscribedmember['username'], $post['username'], $subject, $excerpt, $mybb->settings['bburl'], str_replace("&", "&", get_thread_link($thread['tid'], 0, "newpost")), $thread['tid']), 1314 'touid' => $subscribedmember['uid'], 1315 'language' => $subscribedmember['language'], 1316 'language_file' => 'messages' 1317 ); 1318 // Workaround for eliminating PHP warnings in PHP 8. Ref: https://github.com/mybb/mybb/issues/4630#issuecomment-1369144163 1319 $pm['sender']['uid'] = -1; 1320 send_pm($pm, -1, true); 1321 } 1322 } 1323 1324 $plugins->run_hooks('datahandler_post_insert_subscribed', $args); 1325 1326 // Have one or more emails been queued? Update the queue count 1327 if(isset($queued_email) && $queued_email == 1) 1328 { 1329 $cache->update_mailqueue(); 1330 } 1331 1332 $thread_update = array('replies' => '+1'); 1333 1334 // Update counters 1335 update_last_post($post['tid']); 1336 update_forum_counters($post['fid'], array("posts" => "+1")); 1337 update_forum_lastpost($thread['fid']); 1338 } 1339 // Post is stuck in moderation queue 1340 else if($visible == 0) 1341 { 1342 // Update the unapproved posts count for the current thread and current forum 1343 $thread_update = array('unapprovedposts' => '+1'); 1344 update_thread_counters($post['tid'], array("unapprovedposts" => "+1")); 1345 update_forum_counters($post['fid'], array("unapprovedposts" => "+1")); 1346 } 1347 else if($thread['visible'] == 0) 1348 { 1349 // Update the unapproved posts count for the current forum 1350 $thread_update = array('replies' => '+1'); 1351 update_forum_counters($post['fid'], array("unapprovedposts" => "+1")); 1352 } 1353 else if($thread['visible'] == -1) 1354 { 1355 // Update the unapproved posts count for the current forum 1356 $thread_update = array('replies' => '+1'); 1357 update_forum_counters($post['fid'], array("deletedposts" => "+1")); 1358 } 1359 1360 // Update last poster 1361 if($visible == 1 && $thread['visible'] != 1) 1362 { 1363 update_last_post($post['tid']); 1364 } 1365 1366 $query = $db->simple_select("attachments", "COUNT(aid) AS attachmentcount", "pid='{$this->pid}' AND visible='1'"); 1367 $attachmentcount = $db->fetch_field($query, "attachmentcount"); 1368 if($attachmentcount > 0) 1369 { 1370 $thread_update['attachmentcount'] = "+{$attachmentcount}"; 1371 } 1372 update_thread_counters($post['tid'], $thread_update); 1373 1374 // Return the post's pid and whether or not it is visible. 1375 $this->return_values = array( 1376 "pid" => $this->pid, 1377 "visible" => $visible, 1378 "closed" => $closed 1379 ); 1380 1381 $plugins->run_hooks("datahandler_post_insert_post_end", $this); 1382 1383 return $this->return_values; 1384 } 1385 1386 /** 1387 * Validate a thread. 1388 * 1389 * @return boolean True when valid, false when invalid. 1390 */ 1391 function validate_thread() 1392 { 1393 global $mybb, $db, $plugins; 1394 1395 $thread = &$this->data; 1396 1397 // Validate all thread assets. 1398 1399 if(!$thread['savedraft']) 1400 { 1401 $this->verify_post_flooding(); 1402 } 1403 1404 if($this->method == "insert" || array_key_exists('uid', $thread)) 1405 { 1406 $this->verify_author(); 1407 } 1408 1409 if($this->method == "insert" || array_key_exists('prefix', $thread)) 1410 { 1411 $this->verify_prefix(); 1412 } 1413 1414 if($this->method == "insert" || array_key_exists('subject', $thread)) 1415 { 1416 $this->verify_subject(); 1417 } 1418 1419 if($this->method == "insert" || array_key_exists('message', $thread)) 1420 { 1421 $this->verify_message(); 1422 $this->verify_image_count(); 1423 $this->verify_video_count(); 1424 } 1425 1426 if($this->method == "insert" || array_key_exists('dateline', $thread)) 1427 { 1428 $this->verify_dateline(); 1429 } 1430 1431 if($this->method == "insert" || array_key_exists('icon', $thread)) 1432 { 1433 $this->verify_post_icon(); 1434 } 1435 1436 if($this->method == "insert" || array_key_exists('options', $thread)) 1437 { 1438 $this->verify_options(); 1439 } 1440 1441 $plugins->run_hooks("datahandler_post_validate_thread", $this); 1442 1443 // We are done validating, return. 1444 $this->set_validated(true); 1445 if(count($this->get_errors()) > 0) 1446 { 1447 return false; 1448 } 1449 else 1450 { 1451 return true; 1452 } 1453 } 1454 1455 /** 1456 * Insert a thread into the database. 1457 * 1458 * @return array Array of new thread details, tid and visibility. 1459 */ 1460 function insert_thread() 1461 { 1462 global $db, $mybb, $plugins, $cache, $lang; 1463 1464 // Yes, validating is required. 1465 if(!$this->get_validated()) 1466 { 1467 die("The thread needs to be validated before inserting it into the DB."); 1468 } 1469 if(count($this->get_errors()) > 0) 1470 { 1471 die("The thread is not valid."); 1472 } 1473 1474 $thread = &$this->data; 1475 1476 // Fetch the forum this thread is being made in 1477 $query = $db->simple_select("forums", "*", "fid='{$thread['fid']}'"); 1478 $forum = $db->fetch_array($query); 1479 1480 // This thread is being saved as a draft. 1481 if($thread['savedraft']) 1482 { 1483 $visible = -2; 1484 } 1485 1486 // Thread is being made now and we have a bit to do. 1487 else 1488 { 1489 $forumpermissions = forum_permissions($thread['fid'], $thread['uid']); 1490 // Decide on the visibility of this post. 1491 if($forumpermissions['modthreads'] == 1 && !is_moderator($thread['fid'], "", $thread['uid'])) 1492 { 1493 $visible = 0; 1494 } 1495 else 1496 { 1497 $visible = 1; 1498 } 1499 1500 // Are posts from this user being moderated? Change visibility 1501 if($mybb->user['uid'] == $thread['uid'] && $mybb->user['moderateposts'] == 1) 1502 { 1503 $visible = 0; 1504 } 1505 } 1506 1507 // Have a post ID but not a thread ID - fetch thread ID 1508 if(!empty($thread['pid']) && !$thread['tid']) 1509 { 1510 $query = $db->simple_select("posts", "tid", "pid='{$thread['pid']}"); 1511 $thread['tid'] = $db->fetch_field($query, "tid"); 1512 } 1513 1514 if(isset($thread['pid']) && $thread['pid'] > 0) 1515 { 1516 $query = $db->simple_select("posts", "pid", "pid='{$thread['pid']}' AND uid='{$thread['uid']}' AND visible='-2'"); 1517 $draft_check = $db->fetch_field($query, "pid"); 1518 } 1519 else 1520 { 1521 $draft_check = false; 1522 } 1523 1524 // Are we updating a post which is already a draft? Perhaps changing it into a visible post? 1525 if($draft_check) 1526 { 1527 $this->thread_insert_data = array( 1528 "subject" => $db->escape_string($thread['subject']), 1529 "icon" => (int)$thread['icon'], 1530 "username" => $db->escape_string($thread['username']), 1531 "dateline" => (int)$thread['dateline'], 1532 "lastpost" => (int)$thread['dateline'], 1533 "lastposter" => $db->escape_string($thread['username']), 1534 "visible" => $visible 1535 ); 1536 1537 $plugins->run_hooks("datahandler_post_insert_thread", $this); 1538 1539 $db->update_query("threads", $this->thread_insert_data, "tid='{$thread['tid']}'"); 1540 1541 $this->post_insert_data = array( 1542 "subject" => $db->escape_string($thread['subject']), 1543 "icon" => (int)$thread['icon'], 1544 "username" => $db->escape_string($thread['username']), 1545 "dateline" => (int)$thread['dateline'], 1546 "message" => $db->escape_string($thread['message']), 1547 "ipaddress" => $db->escape_binary(my_inet_pton(get_ip())), 1548 "includesig" => $thread['options']['signature'], 1549 "smilieoff" => $thread['options']['disablesmilies'], 1550 "visible" => $visible 1551 ); 1552 $plugins->run_hooks("datahandler_post_insert_thread_post", $this); 1553 1554 $db->update_query("posts", $this->post_insert_data, "pid='{$thread['pid']}'"); 1555 $this->tid = $thread['tid']; 1556 $this->pid = $thread['pid']; 1557 } 1558 1559 // Inserting a new thread into the database. 1560 else 1561 { 1562 $this->thread_insert_data = array( 1563 "fid" => $thread['fid'], 1564 "subject" => $db->escape_string($thread['subject']), 1565 "prefix" => (int)$thread['prefix'], 1566 "icon" => (int)$thread['icon'], 1567 "uid" => $thread['uid'], 1568 "username" => $db->escape_string($thread['username']), 1569 "dateline" => (int)$thread['dateline'], 1570 "lastpost" => (int)$thread['dateline'], 1571 "lastposter" => $db->escape_string($thread['username']), 1572 "lastposteruid" => $thread['uid'], 1573 "views" => 0, 1574 "replies" => 0, 1575 "visible" => $visible, 1576 "notes" => '' 1577 ); 1578 1579 $plugins->run_hooks("datahandler_post_insert_thread", $this); 1580 1581 $this->tid = $db->insert_query("threads", $this->thread_insert_data); 1582 1583 $this->post_insert_data = array( 1584 "tid" => $this->tid, 1585 "fid" => $thread['fid'], 1586 "subject" => $db->escape_string($thread['subject']), 1587 "icon" => (int)$thread['icon'], 1588 "uid" => $thread['uid'], 1589 "username" => $db->escape_string($thread['username']), 1590 "dateline" => (int)$thread['dateline'], 1591 "message" => $db->escape_string($thread['message']), 1592 "ipaddress" => $db->escape_binary(my_inet_pton(get_ip())), 1593 "includesig" => $thread['options']['signature'], 1594 "smilieoff" => $thread['options']['disablesmilies'], 1595 "visible" => $visible 1596 ); 1597 $plugins->run_hooks("datahandler_post_insert_thread_post", $this); 1598 1599 $this->pid = $db->insert_query("posts", $this->post_insert_data); 1600 1601 // Now that we have the post id for this first post, update the threads table. 1602 $firstpostup = array("firstpost" => $this->pid); 1603 $db->update_query("threads", $firstpostup, "tid='{$this->tid}'"); 1604 } 1605 1606 // If we're not saving a draft there are some things we need to check now 1607 if(!$thread['savedraft']) 1608 { 1609 if($thread['options']['subscriptionmethod'] != "" && $thread['uid'] > 0) 1610 { 1611 switch($thread['options']['subscriptionmethod']) 1612 { 1613 case "pm": 1614 $notification = 2; 1615 break; 1616 case "email": 1617 $notification = 1; 1618 break; 1619 default: 1620 $notification = 0; 1621 } 1622 1623 require_once MYBB_ROOT."inc/functions_user.php"; 1624 add_subscribed_thread($this->tid, $notification, $thread['uid']); 1625 } 1626 1627 // Perform any selected moderation tools. 1628 if(is_moderator($thread['fid'], "", $thread['uid']) && isset($thread['modoptions'])) 1629 { 1630 $lang->load($this->language_file, true); 1631 1632 $modoptions = $thread['modoptions']; 1633 $modlogdata['fid'] = $thread['fid']; 1634 if(isset($thread['tid'])) 1635 { 1636 $modlogdata['tid'] = $thread['tid']; 1637 } 1638 1639 $modoptions_update = array(); 1640 1641 // Close the thread. 1642 if(!empty($modoptions['closethread']) && is_moderator($thread['fid'], "canopenclosethreads", $thread['uid'])) 1643 { 1644 $modoptions_update['closed'] = 1; 1645 log_moderator_action($modlogdata, $lang->thread_closed); 1646 } 1647 1648 // Stick the thread. 1649 if(!empty($modoptions['stickthread']) && is_moderator($thread['fid'], "canstickunstickthreads", $thread['uid'])) 1650 { 1651 $modoptions_update['sticky'] = 1; 1652 log_moderator_action($modlogdata, $lang->thread_stuck); 1653 } 1654 1655 // Execute moderation options. 1656 if($modoptions_update) 1657 { 1658 $db->update_query('threads', $modoptions_update, "tid='{$this->tid}'"); 1659 } 1660 } 1661 if($visible == 1) 1662 { 1663 // If we have a registered user then update their post count and last post times. 1664 if($thread['uid'] > 0) 1665 { 1666 $user = get_user($thread['uid']); 1667 $update_query = array(); 1668 // Only update the lastpost column of the user if the date of the thread is newer than their last post. 1669 if($thread['dateline'] > $user['lastpost']) 1670 { 1671 // Yes this has a single quote within a double quote. It's not a bug. 1672 $update_query['lastpost'] = "'{$thread['dateline']}'"; 1673 } 1674 // Update the post count if this forum allows post counts to be tracked 1675 if($forum['usepostcounts'] != 0) 1676 { 1677 $update_query['postnum'] = "postnum+1"; 1678 } 1679 if($forum['usethreadcounts'] != 0) 1680 { 1681 $update_query['threadnum'] = 'threadnum+1'; 1682 } 1683 1684 // Only update the table if we need to. 1685 if(!empty($update_query)) 1686 { 1687 $db->update_query("users", $update_query, "uid='{$thread['uid']}'", 1, true); 1688 } 1689 } 1690 1691 $done_users = array(); 1692 1693 // Queue up any forum subscription notices to users who are subscribed to this forum. 1694 $excerpt = $thread['message']; 1695 1696 // Parse badwords 1697 require_once MYBB_ROOT."inc/class_parser.php"; 1698 $parser = new postParser; 1699 $excerpt = $parser->parse_badwords($excerpt); 1700 $excerpt = $parser->text_parse_message($excerpt); 1701 if(strlen($excerpt) > $mybb->settings['subscribeexcerpt']) 1702 { 1703 $excerpt = my_substr($excerpt, 0, $mybb->settings['subscribeexcerpt']).$lang->emailbit_viewthread; 1704 } 1705 $query = $db->query(" 1706 SELECT u.username, u.email, u.uid, u.language, u.loginkey, u.salt, u.regdate 1707 FROM ".TABLE_PREFIX."forumsubscriptions fs 1708 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=fs.uid) 1709 LEFT JOIN ".TABLE_PREFIX."usergroups g ON (g.gid=u.usergroup) 1710 WHERE fs.fid='".(int)$thread['fid']."' 1711 AND fs.uid != '".(int)$thread['uid']."' 1712 AND u.lastactive > '{$forum['lastpost']}' 1713 AND g.isbannedgroup != 1 1714 "); 1715 while($subscribedmember = $db->fetch_array($query)) 1716 { 1717 if(!empty($done_users[$subscribedmember['uid']])) 1718 { 1719 continue; 1720 } 1721 $done_users[$subscribedmember['uid']] = 1; 1722 1723 $forumpermissions = forum_permissions($thread['fid'], $subscribedmember['uid']); 1724 if($forumpermissions['canview'] == 0 || $forumpermissions['canviewthreads'] == 0) 1725 { 1726 continue; 1727 } 1728 1729 if(!is_moderator($thread['fid'], "", $subscribedmember['uid']) && $forumpermissions['canonlyviewownthreads'] == 1) 1730 { 1731 // In a 'view own only' forum and not a moderator 1732 continue; 1733 } 1734 1735 // Determine the language pack we'll be using to send this email in and load it if it isn't already. 1736 if($subscribedmember['language'] != '' && $lang->language_exists($subscribedmember['language'])) 1737 { 1738 $uselang = $subscribedmember['language']; 1739 } 1740 else if($mybb->settings['bblanguage']) 1741 { 1742 $uselang = $mybb->settings['bblanguage']; 1743 } 1744 else 1745 { 1746 $uselang = "english"; 1747 } 1748 1749 if($uselang == $mybb->settings['bblanguage']) 1750 { 1751 $emailsubject = $lang->emailsubject_forumsubscription; 1752 $emailmessage = $lang->email_forumsubscription; 1753 1754 // If the poster is unregistered and hasn't set a username, call them Guest 1755 if(!$thread['uid'] && !$thread['username']) 1756 { 1757 $thread['username'] = htmlspecialchars_uni($lang->guest); 1758 } 1759 } 1760 else 1761 { 1762 if(!isset($langcache[$uselang]['emailsubject_forumsubscription'])) 1763 { 1764 $userlang = new MyLanguage; 1765 $userlang->set_path(MYBB_ROOT."inc/languages"); 1766 $userlang->set_language($uselang); 1767 $userlang->load("messages"); 1768 $userlang->load("global"); 1769 $langcache[$uselang]['emailsubject_forumsubscription'] = $userlang->emailsubject_forumsubscription; 1770 $langcache[$uselang]['email_forumsubscription'] = $userlang->email_forumsubscription; 1771 $langcache[$uselang]['guest'] = $userlang->guest; 1772 unset($userlang); 1773 } 1774 $emailsubject = $langcache[$uselang]['emailsubject_forumsubscription']; 1775 $emailmessage = $langcache[$uselang]['email_forumsubscription']; 1776 1777 // If the poster is unregistered and hasn't set a username, call them Guest 1778 if(!$thread['uid'] && !$thread['username']) 1779 { 1780 $thread['username'] = $langcache[$uselang]['guest']; 1781 } 1782 } 1783 $emailsubject = $lang->sprintf($emailsubject, $forum['name']); 1784 1785 $emailmessage = $lang->sprintf($emailmessage, $subscribedmember['username'], $thread['username'], $forum['name'], $mybb->settings['bbname'], $thread['subject'], $excerpt, $mybb->settings['bburl'], get_thread_link($this->tid), $thread['fid']); 1786 $new_email = array( 1787 "mailto" => $db->escape_string($subscribedmember['email']), 1788 "mailfrom" => '', 1789 "subject" => $db->escape_string($emailsubject), 1790 "message" => $db->escape_string($emailmessage), 1791 "headers" => '' 1792 ); 1793 $db->insert_query("mailqueue", $new_email); 1794 unset($userlang); 1795 $queued_email = 1; 1796 } 1797 // Have one or more emails been queued? Update the queue count 1798 if(isset($queued_email) && $queued_email == 1) 1799 { 1800 $cache->update_mailqueue(); 1801 } 1802 } 1803 } 1804 1805 // Assign any uploaded attachments with the specific posthash to the newly created post. 1806 if(!empty($thread['posthash'])) 1807 { 1808 $thread['posthash'] = $db->escape_string($thread['posthash']); 1809 $attachmentassign = array( 1810 "pid" => $this->pid, 1811 "posthash" => '' 1812 ); 1813 $db->update_query("attachments", $attachmentassign, "posthash='{$thread['posthash']}' AND pid='0'"); 1814 } 1815 1816 if($visible == 1) 1817 { 1818 update_last_post($this->tid); 1819 update_forum_counters($thread['fid'], array("threads" => "+1", "posts" => "+1")); 1820 update_forum_lastpost($thread['fid']); 1821 } 1822 else if($visible == 0) 1823 { 1824 update_forum_counters($thread['fid'], array("unapprovedthreads" => "+1", "unapprovedposts" => "+1")); 1825 } 1826 1827 $query = $db->simple_select("attachments", "COUNT(aid) AS attachmentcount", "pid='{$this->pid}' AND visible='1'"); 1828 $attachmentcount = $db->fetch_field($query, "attachmentcount"); 1829 if($attachmentcount > 0) 1830 { 1831 update_thread_counters($this->tid, array("attachmentcount" => "+{$attachmentcount}")); 1832 } 1833 1834 // Return the post's pid and whether or not it is visible. 1835 $this->return_values = array( 1836 "pid" => $this->pid, 1837 "tid" => $this->tid, 1838 "visible" => $visible 1839 ); 1840 1841 $plugins->run_hooks("datahandler_post_insert_thread_end", $this); 1842 1843 return $this->return_values; 1844 } 1845 1846 /** 1847 * Updates a post that is already in the database. 1848 * 1849 * @return array 1850 */ 1851 function update_post() 1852 { 1853 global $db, $mybb, $plugins; 1854 1855 // Yes, validating is required. 1856 if($this->get_validated() != true) 1857 { 1858 die("The post needs to be validated before inserting it into the DB."); 1859 } 1860 if(count($this->get_errors()) > 0) 1861 { 1862 die("The post is not valid."); 1863 } 1864 1865 $post = &$this->data; 1866 1867 $post['pid'] = (int)$post['pid']; 1868 1869 $existing_post = get_post($post['pid']); 1870 $post['tid'] = $existing_post['tid']; 1871 $post['fid'] = $existing_post['fid']; 1872 1873 if(isset($post['uid'])) 1874 { 1875 $uid = $post['uid']; 1876 } 1877 else 1878 { 1879 $uid = 0; 1880 } 1881 1882 $forum = get_forum($post['fid']); 1883 $forumpermissions = forum_permissions($post['fid'], $uid); 1884 1885 // Decide on the visibility of this post. 1886 $ismod = is_moderator($post['fid'], "", $uid); 1887 1888 // Keep visibility for unapproved and deleted posts 1889 if($existing_post['visible'] == 0) 1890 { 1891 $visible = 0; 1892 } 1893 elseif($existing_post['visible'] == -1) 1894 { 1895 $visible = -1; 1896 } 1897 elseif($forumpermissions['mod_edit_posts'] == 1 && !$ismod) 1898 { 1899 $visible = 0; 1900 require_once MYBB_ROOT."inc/class_moderation.php"; 1901 $moderation = new Moderation; 1902 $moderation->unapprove_posts(array($post['pid'])); 1903 } 1904 else 1905 { 1906 $visible = 1; 1907 } 1908 1909 // Update the thread details that might have been changed first. 1910 if($this->first_post) 1911 { 1912 $this->tid = $post['tid']; 1913 1914 if(isset($post['prefix'])) 1915 { 1916 $this->thread_update_data['prefix'] = (int)$post['prefix']; 1917 } 1918 1919 if(isset($post['subject'])) 1920 { 1921 $this->thread_update_data['subject'] = $db->escape_string($post['subject']); 1922 } 1923 1924 if(isset($post['icon'])) 1925 { 1926 $this->thread_update_data['icon'] = (int)$post['icon']; 1927 } 1928 if(count($this->thread_update_data) > 0) 1929 { 1930 $plugins->run_hooks("datahandler_post_update_thread", $this); 1931 1932 $db->update_query("threads", $this->thread_update_data, "tid='".(int)$post['tid']."'"); 1933 } 1934 1935 // Update any moved thread links to have corresponding new subject. 1936 if(isset($post['subject'])) 1937 { 1938 $query = $db->simple_select("threads", "tid, closed", "closed='moved|".$this->tid."'"); 1939 if($db->num_rows($query) > 0) 1940 { 1941 $update_data['subject'] = $db->escape_string($post['subject']); 1942 while($result = $db->fetch_array($query)) 1943 { 1944 $db->update_query("threads", $update_data, "tid='".(int)$result['tid']."'"); 1945 } 1946 } 1947 } 1948 } 1949 1950 // Prepare array for post updating. 1951 1952 $this->pid = $post['pid']; 1953 1954 if(isset($post['subject'])) 1955 { 1956 $this->post_update_data['subject'] = $db->escape_string($post['subject']); 1957 } 1958 1959 if(isset($post['message'])) 1960 { 1961 $this->post_update_data['message'] = $db->escape_string($post['message']); 1962 } 1963 1964 if(isset($post['editreason']) && trim($post['editreason']) != '') 1965 { 1966 $this->post_update_data['editreason'] = $db->escape_string(trim($post['editreason'])); 1967 } 1968 elseif(empty($post['editreason'])) 1969 { 1970 $this->post_update_data['editreason'] = ''; 1971 } 1972 1973 if(isset($post['icon'])) 1974 { 1975 $this->post_update_data['icon'] = (int)$post['icon']; 1976 } 1977 1978 if(isset($post['options'])) 1979 { 1980 if(isset($post['options']['disablesmilies'])) 1981 { 1982 $this->post_update_data['smilieoff'] = $db->escape_string($post['options']['disablesmilies']); 1983 } 1984 if(isset($post['options']['signature'])) 1985 { 1986 $this->post_update_data['includesig'] = $db->escape_string($post['options']['signature']); 1987 } 1988 } 1989 1990 // If we need to show the edited by, let's do so. 1991 if(($mybb->settings['showeditedby'] == 1 && !is_moderator($post['fid'], "caneditposts", $post['edit_uid'])) || ($mybb->settings['showeditedbyadmin'] == 1 && is_moderator($post['fid'], "caneditposts", $post['edit_uid']))) 1992 { 1993 $this->post_update_data['edituid'] = (int)$post['edit_uid']; 1994 $this->post_update_data['edittime'] = TIME_NOW; 1995 } 1996 1997 $plugins->run_hooks("datahandler_post_update", $this); 1998 1999 $db->update_query("posts", $this->post_update_data, "pid='".(int)$post['pid']."'"); 2000 2001 // Automatic subscription to the thread 2002 if($post && !empty($post['options']['subscriptionmethod']) && $uid > 0) 2003 { 2004 switch($post['options']['subscriptionmethod']) 2005 { 2006 case "pm": 2007 $notification = 2; 2008 break; 2009 case "email": 2010 $notification = 1; 2011 break; 2012 default: 2013 $notification = 0; 2014 } 2015 require_once MYBB_ROOT."inc/functions_user.php"; 2016 add_subscribed_thread($post['tid'], $notification, $post['uid']); 2017 } 2018 else 2019 { 2020 $db->delete_query("threadsubscriptions", "uid='".(int)$uid."' AND tid='".(int)$post['tid']."'"); 2021 } 2022 2023 update_forum_lastpost($post['fid']); 2024 update_last_post($post['tid']); 2025 2026 // Return the thread's first post id and whether or not it is visible. 2027 $this->return_values = array( 2028 'visible' => $visible, 2029 'first_post' => $this->first_post 2030 ); 2031 2032 $plugins->run_hooks("datahandler_post_update_end", $this); 2033 2034 return $this->return_values; 2035 } 2036 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup | Cross-referenced by PHPXref |