[ Index ] |
PHP Cross Reference of MyBB 1.8.36 |
[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 * PM handling class, provides common structure to handle private messaging data. 19 * 20 */ 21 class PMDataHandler extends DataHandler 22 { 23 /** 24 * The language file used in the data handler. 25 * 26 * @var string 27 */ 28 public $language_file = 'datahandler_pm'; 29 30 /** 31 * The prefix for the language variables used in the data handler. 32 * 33 * @var string 34 */ 35 public $language_prefix = 'pmdata'; 36 37 /** 38 * Array of data inserted in to a private message. 39 * 40 * @var array 41 */ 42 public $pm_insert_data = array(); 43 44 /** 45 * Array of data used to update a private message. 46 * 47 * @var array 48 */ 49 public $pm_update_data = array(); 50 51 /** 52 * PM ID currently being manipulated by the datahandlers. 53 * 54 * @var int 55 */ 56 public $pmid = 0; 57 58 /** 59 * Values to be returned after inserting a PM. 60 * 61 * @var array 62 */ 63 public $return_values = array(); 64 65 /** 66 * Verifies a private message subject. 67 * 68 * @return boolean True when valid, false when invalid. 69 */ 70 function verify_subject() 71 { 72 $subject = &$this->data['subject']; 73 74 // Subject is over 85 characters, too long. 75 if(my_strlen($subject) > 85) 76 { 77 $this->set_error("too_long_subject"); 78 return false; 79 } 80 // No subject, apply the default [no subject] 81 if(!trim_blank_chrs($subject)) 82 { 83 $this->set_error("missing_subject"); 84 return false; 85 } 86 return true; 87 } 88 89 /** 90 * Verifies if a message for a PM is valid. 91 * 92 * @return boolean True when valid, false when invalid. 93 */ 94 function verify_message() 95 { 96 $message = &$this->data['message']; 97 98 // No message, return an error. 99 if(trim_blank_chrs($message) == '') 100 { 101 $this->set_error("missing_message"); 102 return false; 103 } 104 105 // If the length of message is beyond SQL limitation for 'text' field 106 else if(strlen($message) > 65535) 107 { 108 $this->set_error("message_too_long", array('65535', strlen($message))); 109 return false; 110 } 111 112 return true; 113 } 114 115 /** 116 * Verifies if the specified sender is valid or not. 117 * 118 * @return boolean True when valid, false when invalid. 119 */ 120 function verify_sender() 121 { 122 global $db, $mybb, $lang; 123 124 $pm = &$this->data; 125 126 // Return if we've already validated 127 if(!empty($pm['sender'])) 128 { 129 return true; 130 } 131 132 // Fetch the senders profile data. 133 $sender = get_user($pm['fromid']); 134 135 // Collect user permissions for the sender. 136 $sender_permissions = user_permissions($pm['fromid']); 137 138 // Check if the sender is over their quota or not - if they are, disable draft sending 139 if(isset($pm['options']['savecopy']) && $pm['options']['savecopy'] != 0 && empty($pm['saveasdraft'])) 140 { 141 if($sender_permissions['pmquota'] != 0 && $sender['totalpms'] >= $sender_permissions['pmquota'] && $this->admin_override != true) 142 { 143 $pm['options']['savecopy'] = 0; 144 } 145 } 146 147 // Assign the sender information to the data. 148 $pm['sender'] = array( 149 "uid" => $sender['uid'], 150 "username" => $sender['username'] 151 ); 152 153 return true; 154 } 155 156 /** 157 * Verifies if an array of recipients for a private message are valid 158 * 159 * @return boolean True when valid, false when invalid. 160 */ 161 function verify_recipient() 162 { 163 global $cache, $db, $mybb, $lang; 164 165 $pm = &$this->data; 166 167 $recipients = array(); 168 169 $invalid_recipients = array(); 170 // We have our recipient usernames but need to fetch user IDs 171 if(array_key_exists("to", $pm)) 172 { 173 foreach(array("to", "bcc") as $recipient_type) 174 { 175 if(!isset($pm[$recipient_type])) 176 { 177 $pm[$recipient_type] = array(); 178 } 179 if(!is_array($pm[$recipient_type])) 180 { 181 $pm[$recipient_type] = array($pm[$recipient_type]); 182 } 183 184 $pm[$recipient_type] = array_map('trim', $pm[$recipient_type]); 185 $pm[$recipient_type] = array_filter($pm[$recipient_type]); 186 187 // No recipients? Skip query 188 if(empty($pm[$recipient_type])) 189 { 190 if($recipient_type == 'to' && empty($pm['saveasdraft'])) 191 { 192 $this->set_error("no_recipients"); 193 return false; 194 } 195 continue; 196 } 197 198 $recipientUsernames = array_map(array($db, 'escape_string'), $pm[$recipient_type]); 199 $recipientUsernames = "'".implode("','", $recipientUsernames)."'"; 200 201 $query = $db->simple_select('users', '*', 'username IN('.$recipientUsernames.')'); 202 203 $validUsernames = array(); 204 205 while($user = $db->fetch_array($query)) 206 { 207 if($recipient_type == "bcc") 208 { 209 $user['bcc'] = 1; 210 } 211 212 $recipients[] = $user; 213 $validUsernames[] = $user['username']; 214 } 215 216 foreach($pm[$recipient_type] as $username) 217 { 218 if(!in_array($username, $validUsernames)) 219 { 220 $invalid_recipients[] = $username; 221 } 222 } 223 } 224 } 225 // We have recipient IDs 226 else 227 { 228 foreach(array("toid", "bccid") as $recipient_type) 229 { 230 if(!isset($pm[$recipient_type])) 231 { 232 $pm[$recipient_type] = array(); 233 } 234 if(!is_array($pm[$recipient_type])) 235 { 236 $pm[$recipient_type] = array($pm[$recipient_type]); 237 } 238 $pm[$recipient_type] = array_map('intval', $pm[$recipient_type]); 239 $pm[$recipient_type] = array_filter($pm[$recipient_type]); 240 241 // No recipients? Skip query 242 if(empty($pm[$recipient_type])) 243 { 244 if($recipient_type == 'toid' && !$pm['saveasdraft']) 245 { 246 $this->set_error("no_recipients"); 247 return false; 248 } 249 continue; 250 } 251 252 $recipientUids = "'".implode("','", $pm[$recipient_type])."'"; 253 254 $query = $db->simple_select('users', '*', 'uid IN('.$recipientUids.')'); 255 256 $validUids = array(); 257 258 while($user = $db->fetch_array($query)) 259 { 260 if($recipient_type == "bccid") 261 { 262 $user['bcc'] = 1; 263 } 264 265 $recipients[] = $user; 266 $validUids[] = $user['uid']; 267 } 268 269 foreach($pm[$recipient_type] as $uid) 270 { 271 if(!in_array($uid, $validUids)) 272 { 273 $invalid_recipients[] = $uid; 274 } 275 } 276 } 277 } 278 279 // If we have one or more invalid recipients and we're not saving a draft, error 280 if(count($invalid_recipients) > 0) 281 { 282 $invalid_recipients = implode($lang->comma, array_map("htmlspecialchars_uni", $invalid_recipients)); 283 $this->set_error("invalid_recipients", array($invalid_recipients)); 284 return false; 285 } 286 287 $sender_permissions = user_permissions($pm['fromid']); 288 289 // Are we trying to send this message to more users than the permissions allow? 290 if($sender_permissions['maxpmrecipients'] > 0 && count($recipients) > $sender_permissions['maxpmrecipients'] && $this->admin_override != true) 291 { 292 $this->set_error("too_many_recipients", array($sender_permissions['maxpmrecipients'])); 293 } 294 295 // Now we're done with that we loop through each recipient 296 $pm['recipients'] = array(); 297 foreach($recipients as $user) 298 { 299 // Collect group permissions for this recipient. 300 $recipient_permissions = user_permissions($user['uid']); 301 302 // See if the sender is on the recipients ignore list and that either 303 // - admin_override is set or 304 // - sender is an administrator 305 if($this->admin_override != true && $sender_permissions['canoverridepm'] != 1) 306 { 307 if(!empty($user['ignorelist']) && strpos(','.$user['ignorelist'].',', ','.$pm['fromid'].',') !== false) 308 { 309 $this->set_error("recipient_is_ignoring", array(htmlspecialchars_uni($user['username']))); 310 } 311 312 // Is the recipient only allowing private messages from their buddy list? 313 if(empty($pm['saveasdraft']) && $mybb->settings['allowbuddyonly'] == 1 && $user['receivefrombuddy'] == 1 && !empty($user['buddylist']) && strpos(','.$user['buddylist'].',', ','.$pm['fromid'].',') === false) 314 { 315 $this->set_error('recipient_has_buddy_only', array(htmlspecialchars_uni($user['username']))); 316 } 317 318 // Can the recipient actually receive private messages based on their permissions or user setting? 319 if(($user['receivepms'] == 0 || $recipient_permissions['canusepms'] == 0) && empty($pm['saveasdraft'])) 320 { 321 $this->set_error("recipient_pms_disabled", array(htmlspecialchars_uni($user['username']))); 322 return false; 323 } 324 } 325 326 // Check to see if the user has reached their private message quota - if they have, email them. 327 if($recipient_permissions['pmquota'] != 0 && $user['totalpms'] >= $recipient_permissions['pmquota'] && $sender_permissions['cancp'] != 1 && empty($pm['saveasdraft']) && !$this->admin_override) 328 { 329 if(trim($user['language']) != '' && $lang->language_exists($user['language'])) 330 { 331 $uselang = trim($user['language']); 332 } 333 elseif($mybb->settings['bblanguage']) 334 { 335 $uselang = $mybb->settings['bblanguage']; 336 } 337 else 338 { 339 $uselang = "english"; 340 } 341 if($uselang == $mybb->settings['bblanguage'] || !$uselang) 342 { 343 $emailsubject = $lang->emailsubject_reachedpmquota; 344 $emailmessage = $lang->email_reachedpmquota; 345 } 346 else 347 { 348 $userlang = new MyLanguage; 349 $userlang->set_path(MYBB_ROOT."inc/languages"); 350 $userlang->set_language($uselang); 351 $userlang->load("messages"); 352 $emailsubject = $userlang->emailsubject_reachedpmquota; 353 $emailmessage = $userlang->email_reachedpmquota; 354 } 355 $emailmessage = $lang->sprintf($emailmessage, $user['username'], $mybb->settings['bbname'], $mybb->settings['bburl']); 356 $emailsubject = $lang->sprintf($emailsubject, $mybb->settings['bbname'], $pm['subject']); 357 358 $new_email = array( 359 "mailto" => $db->escape_string($user['email']), 360 "mailfrom" => '', 361 "subject" => $db->escape_string($emailsubject), 362 "message" => $db->escape_string($emailmessage), 363 "headers" => '' 364 ); 365 366 $db->insert_query("mailqueue", $new_email); 367 $cache->update_mailqueue(); 368 369 if($this->admin_override != true) 370 { 371 $this->set_error("recipient_reached_quota", array(htmlspecialchars_uni($user['username']))); 372 } 373 } 374 375 // Everything looks good, assign some specifics about the recipient 376 $pm['recipients'][$user['uid']] = array( 377 "uid" => $user['uid'], 378 "username" => $user['username'], 379 "email" => $user['email'], 380 "lastactive" => $user['lastactive'], 381 "pmnotice" => $user['pmnotice'], 382 "pmnotify" => $user['pmnotify'], 383 "language" => $user['language'] 384 ); 385 386 // If this recipient is defined as a BCC recipient, save it 387 if(isset($user['bcc']) && $user['bcc'] == 1) 388 { 389 $pm['recipients'][$user['uid']]['bcc'] = 1; 390 } 391 } 392 return true; 393 } 394 395 /** 396 * Verify that the user is not flooding the system. 397 * 398 * @return boolean 399 */ 400 function verify_pm_flooding() 401 { 402 global $mybb, $db; 403 404 $pm = &$this->data; 405 406 // Check if post flooding is enabled within MyBB or if the admin override option is specified. 407 if($mybb->settings['pmfloodsecs'] > 0 && $pm['fromid'] != 0 && $this->admin_override == false && !is_moderator(0, '', $pm['fromid'])) 408 { 409 // Fetch the senders profile data. 410 $sender = get_user($pm['fromid']); 411 412 // Calculate last post 413 $query = $db->simple_select("privatemessages", "dateline", "fromid='".$db->escape_string($pm['fromid'])."' AND toid != '0'", array('order_by' => 'dateline', 'order_dir' => 'desc', 'limit' => 1)); 414 $sender['lastpm'] = $db->fetch_field($query, "dateline"); 415 416 // A little bit of calculation magic and moderator status checking. 417 if(TIME_NOW-$sender['lastpm'] <= $mybb->settings['pmfloodsecs']) 418 { 419 // Oops, user has been flooding - throw back error message. 420 $time_to_wait = ($mybb->settings['pmfloodsecs'] - (TIME_NOW-$sender['lastpm'])) + 1; 421 if($time_to_wait == 1) 422 { 423 $this->set_error("pm_flooding_one_second"); 424 } 425 else 426 { 427 $this->set_error("pm_flooding", array($time_to_wait)); 428 } 429 return false; 430 } 431 } 432 // All is well that ends well - return true. 433 return true; 434 } 435 436 /** 437 * Verifies if the various 'options' for sending PMs are valid. 438 * 439 * @return boolean True when valid, false when invalid. 440 */ 441 function verify_options() 442 { 443 $options = &$this->data['options']; 444 445 $this->verify_yesno_option($options, 'signature', 1); 446 $this->verify_yesno_option($options, 'savecopy', 1); 447 $this->verify_yesno_option($options, 'disablesmilies', 0); 448 449 // Requesting a read receipt? 450 if(isset($options['readreceipt']) && $options['readreceipt'] == 1) 451 { 452 $options['readreceipt'] = 1; 453 } 454 else 455 { 456 $options['readreceipt'] = 0; 457 } 458 return true; 459 } 460 461 /** 462 * Validate an entire private message. 463 * 464 * @return boolean True when valid, false when invalid. 465 */ 466 function validate_pm() 467 { 468 global $plugins; 469 470 $pm = &$this->data; 471 472 if(empty($pm['savedraft'])) 473 { 474 $this->verify_pm_flooding(); 475 } 476 477 // Verify all PM assets. 478 $this->verify_subject(); 479 480 $this->verify_sender(); 481 482 $this->verify_recipient(); 483 484 $this->verify_message(); 485 486 $this->verify_options(); 487 488 $plugins->run_hooks("datahandler_pm_validate", $this); 489 490 // Choose the appropriate folder to save in. 491 if(!empty($pm['saveasdraft'])) 492 { 493 $pm['folder'] = 3; 494 } 495 else 496 { 497 $pm['folder'] = 1; 498 } 499 500 // We are done validating, return. 501 $this->set_validated(true); 502 if(count($this->get_errors()) > 0) 503 { 504 return false; 505 } 506 else 507 { 508 return true; 509 } 510 } 511 512 /** 513 * Insert a new private message. 514 * 515 * @return array Array of PM useful data. 516 */ 517 function insert_pm() 518 { 519 global $cache, $db, $mybb, $plugins, $lang; 520 521 // Yes, validating is required. 522 if(!$this->get_validated()) 523 { 524 die("The PM needs to be validated before inserting it into the DB."); 525 } 526 if(count($this->get_errors()) > 0) 527 { 528 die("The PM is not valid."); 529 } 530 531 // Assign data to common variable 532 $pm = &$this->data; 533 534 if(empty($pm['pmid'])) 535 { 536 $pm['pmid'] = 0; 537 } 538 $pm['pmid'] = (int)$pm['pmid']; 539 540 if(empty($pm['icon']) || $pm['icon'] < 0) 541 { 542 $pm['icon'] = 0; 543 } 544 545 $uid = 0; 546 547 // Build recipient list 548 $recipient_list = array(); 549 if(isset($pm['recipients']) && is_array($pm['recipients'])) 550 { 551 foreach($pm['recipients'] as $recipient) 552 { 553 if(!empty($recipient['bcc'])) 554 { 555 $recipient_list['bcc'][] = $recipient['uid']; 556 } 557 else 558 { 559 $recipient_list['to'][] = $recipient['uid']; 560 $uid = $recipient['uid']; 561 } 562 } 563 } 564 565 $this->pm_insert_data = array( 566 'fromid' => (int)$pm['sender']['uid'], 567 'folder' => $pm['folder'], 568 'subject' => $db->escape_string($pm['subject']), 569 'icon' => (int)$pm['icon'], 570 'message' => $db->escape_string($pm['message']), 571 'dateline' => TIME_NOW, 572 'status' => 0, 573 'includesig' => $pm['options']['signature'], 574 'smilieoff' => $pm['options']['disablesmilies'], 575 'receipt' => (int)$pm['options']['readreceipt'], 576 'readtime' => 0, 577 'recipients' => $db->escape_string(my_serialize($recipient_list)), 578 'ipaddress' => $db->escape_binary($pm['ipaddress']) 579 ); 580 581 // Check if we're updating a draft or not. 582 $query = $db->simple_select("privatemessages", "pmid, deletetime", "folder='3' AND uid='".(int)$pm['sender']['uid']."' AND pmid='{$pm['pmid']}'"); 583 $draftcheck = $db->fetch_array($query); 584 585 // This PM was previously a draft 586 if(!empty($draftcheck['pmid'])) 587 { 588 if($draftcheck['deletetime']) 589 { 590 // This draft was a reply to a PM 591 $pm['pmid'] = $draftcheck['deletetime']; 592 $pm['do'] = "reply"; 593 } 594 595 // Delete the old draft as we no longer need it 596 $db->delete_query("privatemessages", "pmid='{$draftcheck['pmid']}'"); 597 } 598 599 // Saving this message as a draft 600 if(!empty($pm['saveasdraft'])) 601 { 602 $this->pm_insert_data['uid'] = $pm['sender']['uid']; 603 604 // If this is a reply, then piggyback into the deletetime to let us know in the future 605 if($pm['do'] == "reply" || $pm['do'] == "replyall") 606 { 607 $this->pm_insert_data['deletetime'] = $pm['pmid']; 608 } 609 610 $plugins->run_hooks("datahandler_pm_insert_updatedraft", $this); 611 612 $this->pmid = $db->insert_query("privatemessages", $this->pm_insert_data); 613 614 $plugins->run_hooks("datahandler_pm_insert_updatedraft_commit", $this); 615 616 // If this is a draft, end it here - below deals with complete messages 617 return array( 618 "draftsaved" => 1 619 ); 620 } 621 622 $this->pmid = array(); 623 624 // Save a copy of the PM for each of our recipients 625 foreach($pm['recipients'] as $recipient) 626 { 627 // Send email notification of new PM if it is enabled for the recipient 628 $query = $db->simple_select("privatemessages", "dateline", "uid='".$recipient['uid']."' AND folder='1'", array('order_by' => 'dateline', 'order_dir' => 'desc', 'limit' => 1)); 629 $lastpm = $db->fetch_array($query); 630 if($recipient['pmnotify'] == 1 && (empty($lastpm['dateline']) || $recipient['lastactive'] > $lastpm['dateline'])) 631 { 632 if($recipient['language'] != "" && $lang->language_exists($recipient['language'])) 633 { 634 $uselang = $recipient['language']; 635 } 636 elseif($mybb->settings['bblanguage']) 637 { 638 $uselang = $mybb->settings['bblanguage']; 639 } 640 else 641 { 642 $uselang = "english"; 643 } 644 if($uselang == $mybb->settings['bblanguage'] && !empty($lang->emailsubject_newpm)) 645 { 646 $emailsubject = $lang->emailsubject_newpm; 647 $emailmessage = $lang->email_newpm; 648 } 649 else 650 { 651 $userlang = new MyLanguage; 652 $userlang->set_path(MYBB_ROOT."inc/languages"); 653 $userlang->set_language($uselang); 654 $userlang->load("messages"); 655 $emailsubject = $userlang->emailsubject_newpm; 656 $emailmessage = $userlang->email_newpm; 657 } 658 659 if(!$pm['sender']['username']) 660 { 661 $pm['sender']['username'] = $lang->mybb_engine; 662 } 663 664 require_once MYBB_ROOT.'inc/class_parser.php'; 665 $parser = new Postparser; 666 667 $parser_options = array( 668 'me_username' => $pm['sender']['username'], 669 'filter_badwords' => 1 670 ); 671 672 $pm['message'] = $parser->text_parse_message($pm['message'], $parser_options); 673 674 $emailmessage = $lang->sprintf($emailmessage, $recipient['username'], $pm['sender']['username'], $mybb->settings['bbname'], $mybb->settings['bburl'], $pm['message']); 675 $emailsubject = $lang->sprintf($emailsubject, $mybb->settings['bbname'], $pm['subject']); 676 677 $new_email = array( 678 "mailto" => $db->escape_string($recipient['email']), 679 "mailfrom" => '', 680 "subject" => $db->escape_string($emailsubject), 681 "message" => $db->escape_string($emailmessage), 682 "headers" => '' 683 ); 684 685 $db->insert_query("mailqueue", $new_email); 686 $cache->update_mailqueue(); 687 } 688 689 $this->pm_insert_data['uid'] = $recipient['uid']; 690 $this->pm_insert_data['toid'] = $recipient['uid']; 691 692 $plugins->run_hooks("datahandler_pm_insert", $this); 693 694 $this->pmid[] = $db->insert_query("privatemessages", $this->pm_insert_data); 695 696 $plugins->run_hooks("datahandler_pm_insert_commit", $this); 697 698 // If PM noices/alerts are on, show! 699 if($recipient['pmnotice'] == 1) 700 { 701 $updated_user = array( 702 "pmnotice" => 2 703 ); 704 $db->update_query("users", $updated_user, "uid='{$recipient['uid']}'"); 705 } 706 707 // Update private message count (total, new and unread) for recipient 708 require_once MYBB_ROOT."/inc/functions_user.php"; 709 update_pm_count($recipient['uid'], 7, $recipient['lastactive']); 710 } 711 712 // Are we replying or forwarding an existing PM? 713 if($pm['pmid']) 714 { 715 if($pm['do'] == "reply" || $pm['do'] == "replyall") 716 { 717 $sql_array = array( 718 'status' => 3, 719 'statustime' => TIME_NOW 720 ); 721 $db->update_query("privatemessages", $sql_array, "pmid={$pm['pmid']} AND uid={$pm['sender']['uid']}"); 722 } 723 elseif($pm['do'] == "forward") 724 { 725 $sql_array = array( 726 'status' => 4, 727 'statustime' => TIME_NOW 728 ); 729 $db->update_query("privatemessages", $sql_array, "pmid={$pm['pmid']} AND uid={$pm['sender']['uid']}"); 730 } 731 } 732 733 // If we're saving a copy 734 if($pm['options']['savecopy'] != 0) 735 { 736 if(isset($recipient_list['to']) && is_array($recipient_list['to']) && count($recipient_list['to']) == 1) 737 { 738 $this->pm_insert_data['toid'] = $uid; 739 } 740 else 741 { 742 $this->pm_insert_data['toid'] = 0; 743 } 744 $this->pm_insert_data['uid'] = (int)$pm['sender']['uid']; 745 $this->pm_insert_data['folder'] = 2; 746 $this->pm_insert_data['status'] = 1; 747 $this->pm_insert_data['receipt'] = 0; 748 749 $plugins->run_hooks("datahandler_pm_insert_savedcopy", $this); 750 751 $db->insert_query("privatemessages", $this->pm_insert_data); 752 753 $plugins->run_hooks("datahandler_pm_insert_savedcopy_commit", $this); 754 755 // Because the sender saved a copy, update their total pm count 756 require_once MYBB_ROOT."/inc/functions_user.php"; 757 update_pm_count($pm['sender']['uid'], 1); 758 } 759 760 // Return back with appropriate data 761 $this->return_values = array( 762 "messagesent" => 1, 763 "pmids" => $this->pmid 764 ); 765 766 $plugins->run_hooks("datahandler_pm_insert_end", $this); 767 768 return $this->return_values; 769 } 770 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup | Cross-referenced by PHPXref |