| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?php 2 //////////////////////////////////////////////////// 3 // PHPMailer - PHP email class 4 // 5 // Class for sending email using either 6 // sendmail, PHP mail(), or SMTP. Methods are 7 // based upon the standard AspEmail(tm) classes. 8 // 9 // Copyright (C) 2001 - 2003 Brent R. Matzelle 10 // 11 // License: LGPL, see LICENSE 12 //////////////////////////////////////////////////// 13 14 /** 15 * PHPMailer - PHP email transport class 16 * @package PHPMailer 17 * @author Brent R. Matzelle 18 * @copyright 2001 - 2003 Brent R. Matzelle 19 */ 20 class PHPMailer 21 { 22 ///////////////////////////////////////////////// 23 // PUBLIC VARIABLES 24 ///////////////////////////////////////////////// 25 26 /** 27 * Email priority (1 = High, 3 = Normal, 5 = low). 28 * @var int 29 */ 30 var $Priority = 3; 31 32 /** 33 * Sets the CharSet of the message. 34 * @var string 35 */ 36 var $CharSet = "iso-8859-1"; 37 38 /** 39 * Sets the Content-type of the message. 40 * @var string 41 */ 42 var $ContentType = "text/plain"; 43 44 /** 45 * Sets the Encoding of the message. Options for this are "8bit", 46 * "7bit", "binary", "base64", and "quoted-printable". 47 * @var string 48 */ 49 var $Encoding = "8bit"; 50 51 /** 52 * Holds the most recent mailer error message. 53 * @var string 54 */ 55 var $ErrorInfo = ""; 56 57 /** 58 * Sets the From email address for the message. 59 * @var string 60 */ 61 var $From = "root@localhost"; 62 63 /** 64 * Sets the From name of the message. 65 * @var string 66 */ 67 var $FromName = "Root User"; 68 69 /** 70 * Sets the Sender email (Return-Path) of the message. If not empty, 71 * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. 72 * @var string 73 */ 74 var $Sender = ""; 75 76 /** 77 * Sets the Subject of the message. 78 * @var string 79 */ 80 var $Subject = ""; 81 82 /** 83 * Sets the Body of the message. This can be either an HTML or text body. 84 * If HTML then run IsHTML(true). 85 * @var string 86 */ 87 var $Body = ""; 88 89 /** 90 * Sets the text-only body of the message. This automatically sets the 91 * email to multipart/alternative. This body can be read by mail 92 * clients that do not have HTML email capability such as mutt. Clients 93 * that can read HTML will view the normal Body. 94 * @var string 95 */ 96 var $AltBody = ""; 97 98 /** 99 * Sets word wrapping on the body of the message to a given number of 100 * characters. 101 * @var int 102 */ 103 var $WordWrap = 0; 104 105 /** 106 * Method to send mail: ("mail", "sendmail", or "smtp"). 107 * @var string 108 */ 109 var $Mailer = "mail"; 110 111 /** 112 * Sets the path of the sendmail program. 113 * @var string 114 */ 115 var $Sendmail = "/usr/sbin/sendmail"; 116 117 /** 118 * Path to PHPMailer plugins. This is now only useful if the SMTP class 119 * is in a different directory than the PHP include path. 120 * @var string 121 */ 122 var $PluginDir = ""; 123 124 /** 125 * Holds PHPMailer version. 126 * @var string 127 */ 128 var $Version = "1.73"; 129 130 /** 131 * Sets the email address that a reading confirmation will be sent. 132 * @var string 133 */ 134 var $ConfirmReadingTo = ""; 135 136 /** 137 * Sets the hostname to use in Message-Id and Received headers 138 * and as default HELO string. If empty, the value returned 139 * by SERVER_NAME is used or 'localhost.localdomain'. 140 * @var string 141 */ 142 var $Hostname = ""; 143 144 ///////////////////////////////////////////////// 145 // SMTP VARIABLES 146 ///////////////////////////////////////////////// 147 148 /** 149 * Sets the SMTP hosts. All hosts must be separated by a 150 * semicolon. You can also specify a different port 151 * for each host by using this format: [hostname:port] 152 * (e.g. "smtp1.example.com:25;smtp2.example.com"). 153 * Hosts will be tried in order. 154 * @var string 155 */ 156 var $Host = "localhost"; 157 158 /** 159 * Sets the default SMTP server port. 160 * @var int 161 */ 162 var $Port = 25; 163 164 /** 165 * Sets the SMTP HELO of the message (Default is $Hostname). 166 * @var string 167 */ 168 var $Helo = ""; 169 170 /** 171 * Sets SMTP authentication. Utilizes the Username and Password variables. 172 * @var bool 173 */ 174 var $SMTPAuth = false; 175 176 /** 177 * Sets SMTP username. 178 * @var string 179 */ 180 var $Username = ""; 181 182 /** 183 * Sets SMTP password. 184 * @var string 185 */ 186 var $Password = ""; 187 188 /** 189 * Sets the SMTP server timeout in seconds. This function will not 190 * work with the win32 version. 191 * @var int 192 */ 193 var $Timeout = 10; 194 195 /** 196 * Sets SMTP class debugging on or off. 197 * @var bool 198 */ 199 var $SMTPDebug = false; 200 201 /** 202 * Prevents the SMTP connection from being closed after each mail 203 * sending. If this is set to true then to close the connection 204 * requires an explicit call to SmtpClose(). 205 * @var bool 206 */ 207 var $SMTPKeepAlive = false; 208 209 /**#@+ 210 * @access private 211 */ 212 var $smtp = NULL; 213 var $to = array(); 214 var $cc = array(); 215 var $bcc = array(); 216 var $ReplyTo = array(); 217 var $attachment = array(); 218 var $CustomHeader = array(); 219 var $message_type = ""; 220 var $boundary = array(); 221 var $language = array(); 222 var $error_count = 0; 223 var $LE = "\n"; 224 /**#@-*/ 225 226 ///////////////////////////////////////////////// 227 // VARIABLE METHODS 228 ///////////////////////////////////////////////// 229 230 /** 231 * Constructor 232 * Hack for Moodle as class may be included from various locations 233 * SE 20041001 234 * @param void 235 * @return void 236 */ 237 function PHPMailer () { 238 global $CFG; 239 $this->PluginDir = $CFG->libdir.'/phpmailer/'; 240 } 241 242 243 244 /** 245 * Sets message type to HTML. 246 * @param bool $bool 247 * @return void 248 */ 249 function IsHTML($bool) { 250 if($bool == true) 251 $this->ContentType = "text/html"; 252 else 253 $this->ContentType = "text/plain"; 254 } 255 256 /** 257 * Sets Mailer to send message using SMTP. 258 * @return void 259 */ 260 function IsSMTP() { 261 $this->Mailer = "smtp"; 262 } 263 264 /** 265 * Sets Mailer to send message using PHP mail() function. 266 * @return void 267 */ 268 function IsMail() { 269 $this->Mailer = "mail"; 270 } 271 272 /** 273 * Sets Mailer to send message using the $Sendmail program. 274 * @return void 275 */ 276 function IsSendmail() { 277 $this->Mailer = "sendmail"; 278 } 279 280 /** 281 * Sets Mailer to send message using the qmail MTA. 282 * @return void 283 */ 284 function IsQmail() { 285 $this->Sendmail = "/var/qmail/bin/sendmail"; 286 $this->Mailer = "sendmail"; 287 } 288 289 290 ///////////////////////////////////////////////// 291 // RECIPIENT METHODS 292 ///////////////////////////////////////////////// 293 294 /** 295 * Adds a "To" address. 296 * @param string $address 297 * @param string $name 298 * @return void 299 */ 300 function AddAddress($address, $name = "") { 301 $cur = count($this->to); 302 $this->to[$cur][0] = trim($address); 303 $this->to[$cur][1] = $name; 304 } 305 306 /** 307 * Adds a "Cc" address. Note: this function works 308 * with the SMTP mailer on win32, not with the "mail" 309 * mailer. 310 * @param string $address 311 * @param string $name 312 * @return void 313 */ 314 function AddCC($address, $name = "") { 315 $cur = count($this->cc); 316 $this->cc[$cur][0] = trim($address); 317 $this->cc[$cur][1] = $name; 318 } 319 320 /** 321 * Adds a "Bcc" address. Note: this function works 322 * with the SMTP mailer on win32, not with the "mail" 323 * mailer. 324 * @param string $address 325 * @param string $name 326 * @return void 327 */ 328 function AddBCC($address, $name = "") { 329 $cur = count($this->bcc); 330 $this->bcc[$cur][0] = trim($address); 331 $this->bcc[$cur][1] = $name; 332 } 333 334 /** 335 * Adds a "Reply-to" address. 336 * @param string $address 337 * @param string $name 338 * @return void 339 */ 340 function AddReplyTo($address, $name = "") { 341 $cur = count($this->ReplyTo); 342 $this->ReplyTo[$cur][0] = trim($address); 343 $this->ReplyTo[$cur][1] = $name; 344 } 345 346 347 ///////////////////////////////////////////////// 348 // MAIL SENDING METHODS 349 ///////////////////////////////////////////////// 350 351 /** 352 * Creates message and assigns Mailer. If the message is 353 * not sent successfully then it returns false. Use the ErrorInfo 354 * variable to view description of the error. 355 * @return bool 356 */ 357 function Send() { 358 $header = ""; 359 $body = ""; 360 $result = true; 361 362 if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) 363 { 364 $this->SetError($this->Lang("provide_address")); 365 return false; 366 } 367 368 // Set whether the message is multipart/alternative 369 if(!empty($this->AltBody)) 370 $this->ContentType = "multipart/alternative"; 371 372 $this->error_count = 0; // reset errors 373 $this->SetMessageType(); 374 $header .= $this->CreateHeader(); 375 $body = $this->CreateBody(); 376 377 if($body == "") { return false; } 378 379 // Choose the mailer 380 switch($this->Mailer) 381 { 382 case "sendmail": 383 $result = $this->SendmailSend($header, $body); 384 break; 385 case "mail": 386 $result = $this->MailSend($header, $body); 387 break; 388 case "smtp": 389 $result = $this->SmtpSend($header, $body); 390 break; 391 default: 392 $this->SetError($this->Mailer . $this->Lang("mailer_not_supported")); 393 $result = false; 394 break; 395 } 396 397 return $result; 398 } 399 400 /** 401 * Sends mail using the $Sendmail program. 402 * @access private 403 * @return bool 404 */ 405 function SendmailSend($header, $body) { 406 if ($this->Sender != "") 407 $sendmail = sprintf("%s -oi -f %s -t", $this->Sendmail, $this->Sender); 408 else 409 $sendmail = sprintf("%s -oi -t", $this->Sendmail); 410 411 if(!@$mail = popen($sendmail, "w")) 412 { 413 $this->SetError($this->Lang("execute") . $this->Sendmail); 414 return false; 415 } 416 417 fputs($mail, $header); 418 fputs($mail, $body); 419 420 $result = pclose($mail) >> 8 & 0xFF; 421 if($result != 0) 422 { 423 $this->SetError($this->Lang("execute") . $this->Sendmail); 424 return false; 425 } 426 427 return true; 428 } 429 430 /** 431 * Sends mail using the PHP mail() function. 432 * @access private 433 * @return bool 434 */ 435 function MailSend($header, $body) { 436 $to = ""; 437 for($i = 0; $i < count($this->to); $i++) 438 { 439 if($i != 0) { $to .= ", "; } 440 $to .= $this->to[$i][0]; 441 } 442 443 if ($this->Sender != "" && strlen(ini_get("safe_mode"))< 1) 444 { 445 $old_from = ini_get("sendmail_from"); 446 ini_set("sendmail_from", $this->Sender); 447 $params = sprintf("-oi -f %s", $this->Sender); 448 $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, 449 $header, $params); 450 } 451 else 452 $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, $header); 453 454 if (isset($old_from)) 455 ini_set("sendmail_from", $old_from); 456 457 if(!$rt) 458 { 459 $this->SetError($this->Lang("instantiate")); 460 return false; 461 } 462 463 return true; 464 } 465 466 /** 467 * Sends mail via SMTP using PhpSMTP (Author: 468 * Chris Ryan). Returns bool. Returns false if there is a 469 * bad MAIL FROM, RCPT, or DATA input. 470 * @access private 471 * @return bool 472 */ 473 function SmtpSend($header, $body) { 474 include_once($this->PluginDir."class.smtp.php"); 475 $error = ""; 476 $bad_rcpt = array(); 477 478 if(!$this->SmtpConnect()) 479 return false; 480 481 $smtp_from = ($this->Sender == "") ? $this->From : $this->Sender; 482 if(!$this->smtp->Mail($smtp_from)) 483 { 484 $error = $this->Lang("from_failed") . $smtp_from; 485 $this->SetError($error); 486 $this->smtp->Reset(); 487 return false; 488 } 489 490 // Attempt to send attach all recipients 491 for($i = 0; $i < count($this->to); $i++) 492 { 493 if(!$this->smtp->Recipient($this->to[$i][0])) 494 $bad_rcpt[] = $this->to[$i][0]; 495 } 496 for($i = 0; $i < count($this->cc); $i++) 497 { 498 if(!$this->smtp->Recipient($this->cc[$i][0])) 499 $bad_rcpt[] = $this->cc[$i][0]; 500 } 501 for($i = 0; $i < count($this->bcc); $i++) 502 { 503 if(!$this->smtp->Recipient($this->bcc[$i][0])) 504 $bad_rcpt[] = $this->bcc[$i][0]; 505 } 506 507 if(count($bad_rcpt) > 0) // Create error message 508 { 509 for($i = 0; $i < count($bad_rcpt); $i++) 510 { 511 if($i != 0) { $error .= ", "; } 512 $error .= $bad_rcpt[$i]; 513 } 514 $error = $this->Lang("recipients_failed") . $error; 515 $this->SetError($error); 516 $this->smtp->Reset(); 517 return false; 518 } 519 520 if(!$this->smtp->Data($header . $body)) 521 { 522 $this->SetError($this->Lang("data_not_accepted")); 523 $this->smtp->Reset(); 524 return false; 525 } 526 if($this->SMTPKeepAlive == true) 527 $this->smtp->Reset(); 528 else 529 $this->SmtpClose(); 530 531 return true; 532 } 533 534 /** 535 * Initiates a connection to an SMTP server. Returns false if the 536 * operation failed. 537 * @access private 538 * @return bool 539 */ 540 function SmtpConnect() { 541 if($this->smtp == NULL) { $this->smtp = new SMTP(); } 542 543 $this->smtp->do_debug = $this->SMTPDebug; 544 $hosts = explode(";", $this->Host); 545 $index = 0; 546 $connection = ($this->smtp->Connected()); 547 548 // Retry while there is no connection 549 while($index < count($hosts) && $connection == false) 550 { 551 if(strstr($hosts[$index], ":")) 552 list($host, $port) = explode(":", $hosts[$index]); 553 else 554 { 555 $host = $hosts[$index]; 556 $port = $this->Port; 557 } 558 559 if($this->smtp->Connect($host, $port, $this->Timeout)) 560 { 561 if ($this->Helo != '') 562 $this->smtp->Hello($this->Helo); 563 else 564 $this->smtp->Hello($this->ServerHostname()); 565 566 if($this->SMTPAuth) 567 { 568 if(!$this->smtp->Authenticate($this->Username, 569 $this->Password)) 570 { 571 $this->SetError($this->Lang("authenticate")); 572 $this->smtp->Reset(); 573 $connection = false; 574 } 575 } 576 $connection = true; 577 } 578 $index++; 579 } 580 if(!$connection) 581 $this->SetError($this->Lang("connect_host")); 582 583 return $connection; 584 } 585 586 /** 587 * Closes the active SMTP session if one exists. 588 * @return void 589 */ 590 function SmtpClose() { 591 if($this->smtp != NULL) 592 { 593 if($this->smtp->Connected()) 594 { 595 $this->smtp->Quit(); 596 $this->smtp->Close(); 597 } 598 } 599 } 600 601 /** 602 * Sets the language for all class error messages. Returns false 603 * if it cannot load the language file. The default language type 604 * is English. 605 * SE 20041001: Added '$this->PluginDir' for Moodle compatibility 606 * 607 * @param string $lang_type Type of language (e.g. Portuguese: "br") 608 * @param string $lang_path Path to the language file directory 609 * @access public 610 * @return bool 611 */ 612 function SetLanguage($lang_type, $lang_path = "language/") { 613 if(file_exists($this->PluginDir.$lang_path.'phpmailer.lang-'.$lang_type.'.php')) 614 include($this->PluginDir.$lang_path.'phpmailer.lang-'.$lang_type.'.php'); 615 else if(file_exists($lang_path.'phpmailer.lang-en.php')) 616 include($this->PluginDir.$lang_path.'phpmailer.lang-en.php'); 617 else 618 { 619 $this->SetError("Could not load language file"); 620 return false; 621 } 622 $this->language = $PHPMAILER_LANG; 623 624 return true; 625 } 626 627 ///////////////////////////////////////////////// 628 // MESSAGE CREATION METHODS 629 ///////////////////////////////////////////////// 630 631 /** 632 * Creates recipient headers. 633 * @access private 634 * @return string 635 */ 636 function AddrAppend($type, $addr) { 637 $addr_str = $type . ": "; 638 $addr_str .= $this->AddrFormat($addr[0]); 639 if(count($addr) > 1) 640 { 641 for($i = 1; $i < count($addr); $i++) 642 $addr_str .= ", " . $this->AddrFormat($addr[$i]); 643 } 644 $addr_str .= $this->LE; 645 646 return $addr_str; 647 } 648 649 /** 650 * Formats an address correctly. 651 * @access private 652 * @return string 653 */ 654 function AddrFormat($addr) { 655 if(empty($addr[1])) 656 $formatted = $addr[0]; 657 else 658 { 659 $formatted = $this->EncodeHeader($addr[1], 'phrase') . " <" . 660 $addr[0] . ">"; 661 } 662 663 return $formatted; 664 } 665 666 /** 667 * Wraps message for use with mailers that do not 668 * automatically perform wrapping and for quoted-printable. 669 * Original written by philippe. 670 * @access private 671 * @return string 672 */ 673 function WrapText($message, $length, $qp_mode = false) { 674 $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE; 675 676 $message = $this->FixEOL($message); 677 if (substr($message, -1) == $this->LE) 678 $message = substr($message, 0, -1); 679 680 $line = explode($this->LE, $message); 681 $message = ""; 682 for ($i=0 ;$i < count($line); $i++) 683 { 684 $line_part = explode(" ", $line[$i]); 685 $buf = ""; 686 for ($e = 0; $e<count($line_part); $e++) 687 { 688 $word = $line_part[$e]; 689 if ($qp_mode and (strlen($word) > $length)) 690 { 691 $space_left = $length - strlen($buf) - 1; 692 if ($e != 0) 693 { 694 if ($space_left > 20) 695 { 696 $len = $space_left; 697 if (substr($word, $len - 1, 1) == "=") 698 $len--; 699 elseif (substr($word, $len - 2, 1) == "=") 700 $len -= 2; 701 $part = substr($word, 0, $len); 702 $word = substr($word, $len); 703 $buf .= " " . $part; 704 $message .= $buf . sprintf("=%s", $this->LE); 705 } 706 else 707 { 708 $message .= $buf . $soft_break; 709 } 710 $buf = ""; 711 } 712 while (strlen($word) > 0) 713 { 714 $len = $length; 715 if (substr($word, $len - 1, 1) == "=") 716 $len--; 717 elseif (substr($word, $len - 2, 1) == "=") 718 $len -= 2; 719 $part = substr($word, 0, $len); 720 $word = substr($word, $len); 721 722 if (strlen($word) > 0) 723 $message .= $part . sprintf("=%s", $this->LE); 724 else 725 $buf = $part; 726 } 727 } 728 else 729 { 730 $buf_o = $buf; 731 $buf .= ($e == 0) ? $word : (" " . $word); 732 733 if (strlen($buf) > $length and $buf_o != "") 734 { 735 $message .= $buf_o . $soft_break; 736 $buf = $word; 737 } 738 } 739 } 740 $message .= $buf . $this->LE; 741 } 742 743 return $message; 744 } 745 746 /** 747 * Set the body wrapping. 748 * @access private 749 * @return void 750 */ 751 function SetWordWrap() { 752 if($this->WordWrap < 1) 753 return; 754 755 switch($this->message_type) 756 { 757 case "alt": 758 // fall through 759 case "alt_attachments": 760 $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap); 761 break; 762 default: 763 $this->Body = $this->WrapText($this->Body, $this->WordWrap); 764 break; 765 } 766 } 767 768 /** 769 * Assembles message header. 770 * @access private 771 * @return string 772 */ 773 function CreateHeader() { 774 $result = ""; 775 776 // Set the boundaries 777 $uniq_id = md5(uniqid(time())); 778 $this->boundary[1] = "b1_" . $uniq_id; 779 $this->boundary[2] = "b2_" . $uniq_id; 780 781 $result .= $this->HeaderLine("Date", $this->RFCDate()); 782 if($this->Sender == "") 783 $result .= $this->HeaderLine("Return-Path", trim($this->From)); 784 else 785 $result .= $this->HeaderLine("Return-Path", trim($this->Sender)); 786 787 // To be created automatically by mail() 788 if($this->Mailer != "mail") 789 { 790 if(count($this->to) > 0) 791 $result .= $this->AddrAppend("To", $this->to); 792 else if (count($this->cc) == 0) 793 $result .= $this->HeaderLine("To", "undisclosed-recipients:;"); 794 if(count($this->cc) > 0) 795 $result .= $this->AddrAppend("Cc", $this->cc); 796 } 797 798 $from = array(); 799 $from[0][0] = trim($this->From); 800 $from[0][1] = $this->FromName; 801 $result .= $this->AddrAppend("From", $from); 802 803 // sendmail and mail() extract Bcc from the header before sending 804 if((($this->Mailer == "sendmail") || ($this->Mailer == "mail")) && (count($this->bcc) > 0)) 805 $result .= $this->AddrAppend("Bcc", $this->bcc); 806 807 if(count($this->ReplyTo) > 0) 808 $result .= $this->AddrAppend("Reply-to", $this->ReplyTo); 809 810 // mail() sets the subject itself 811 if($this->Mailer != "mail") 812 $result .= $this->HeaderLine("Subject", $this->EncodeHeader(trim($this->Subject))); 813 814 /** 815 * BEGIN original phpmailer code 816 * 817 * Commented out is the original line we are replacing. 818 * Vy-Shane Sin Fat <vy-shane At moodle.com>, 14 Feb 2007. 819 */ 820 //$result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); 821 /** 822 * END original phpmailer code 823 */ 824 825 /** 826 * BEGIN custom Moodle code 827 * 828 * This change is made necessary by MDL-3681. The Moodle forum module 829 * adds Message-ID as a custom header for each forum post mailout. 830 * This is used to help email clients display the messages in a 831 * threaded view. However, phpmailer also adds it's own Message-ID 832 * to every email that it sends. We want this to happen only if we 833 * haven't defined our own custom Message-ID for the email. 834 * 835 * Vy-Shane Sin Fat <vy-shane At moodle.com>, 14 Feb 2007. 836 */ 837 $needmessageid = true; 838 839 for($i=0; $i<count($this->CustomHeader); $i++) 840 { 841 if (strtolower(trim($this->CustomHeader[$i][0])) == 'message-id') { 842 $needmessageid = false; 843 break; 844 } 845 } 846 if ($needmessageid) { 847 $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); 848 } 849 /** 850 * END custom Moodle code 851 */ 852 853 $result .= $this->HeaderLine("X-Priority", $this->Priority); 854 $result .= $this->HeaderLine("X-Mailer", "PHPMailer [version " . $this->Version . "]"); 855 856 if($this->ConfirmReadingTo != "") 857 { 858 $result .= $this->HeaderLine("Disposition-Notification-To", 859 "<" . trim($this->ConfirmReadingTo) . ">"); 860 } 861 862 // Add custom headers 863 for($index = 0; $index < count($this->CustomHeader); $index++) 864 { 865 $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), 866 $this->EncodeHeader(trim($this->CustomHeader[$index][1]))); 867 } 868 $result .= $this->HeaderLine("MIME-Version", "1.0"); 869 870 switch($this->message_type) 871 { 872 case "plain": 873 $result .= $this->HeaderLine("Content-Transfer-Encoding", $this->Encoding); 874 $result .= sprintf("Content-Type: %s; charset=\"%s\"", 875 $this->ContentType, $this->CharSet); 876 break; 877 case "attachments": 878 // fall through 879 case "alt_attachments": 880 if($this->InlineImageExists()) 881 { 882 $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 883 "multipart/related", $this->LE, $this->LE, 884 $this->boundary[1], $this->LE); 885 } 886 else 887 { 888 $result .= $this->HeaderLine("Content-Type", "multipart/mixed;"); 889 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); 890 } 891 break; 892 case "alt": 893 $result .= $this->HeaderLine("Content-Type", "multipart/alternative;"); 894 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); 895 break; 896 } 897 898 if($this->Mailer != "mail") 899 $result .= $this->LE.$this->LE; 900 901 return $result; 902 } 903 904 /** 905 * Assembles the message body. Returns an empty string on failure. 906 * @access private 907 * @return string 908 */ 909 function CreateBody() { 910 $result = ""; 911 912 $this->SetWordWrap(); 913 914 switch($this->message_type) 915 { 916 case "alt": 917 $result .= $this->GetBoundary($this->boundary[1], "", 918 "text/plain", ""); 919 $result .= $this->EncodeString($this->AltBody, $this->Encoding); 920 $result .= $this->LE.$this->LE; 921 $result .= $this->GetBoundary($this->boundary[1], "", 922 "text/html", ""); 923 924 $result .= $this->EncodeString($this->Body, $this->Encoding); 925 $result .= $this->LE.$this->LE; 926 927 $result .= $this->EndBoundary($this->boundary[1]); 928 break; 929 case "plain": 930 $result .= $this->EncodeString($this->Body, $this->Encoding); 931 break; 932 case "attachments": 933 $result .= $this->GetBoundary($this->boundary[1], "", "", ""); 934 $result .= $this->EncodeString($this->Body, $this->Encoding); 935 $result .= $this->LE; 936 937 $result .= $this->AttachAll(); 938 break; 939 case "alt_attachments": 940 $result .= sprintf("--%s%s", $this->boundary[1], $this->LE); 941 $result .= sprintf("Content-Type: %s;%s" . 942 "\tboundary=\"%s\"%s", 943 "multipart/alternative", $this->LE, 944 $this->boundary[2], $this->LE.$this->LE); 945 946 // Create text body 947 $result .= $this->GetBoundary($this->boundary[2], "", 948 "text/plain", "") . $this->LE; 949 950 $result .= $this->EncodeString($this->AltBody, $this->Encoding); 951 $result .= $this->LE.$this->LE; 952 953 // Create the HTML body 954 $result .= $this->GetBoundary($this->boundary[2], "", 955 "text/html", "") . $this->LE; 956 957 $result .= $this->EncodeString($this->Body, $this->Encoding); 958 $result .= $this->LE.$this->LE; 959 960 $result .= $this->EndBoundary($this->boundary[2]); 961 962 $result .= $this->AttachAll(); 963 break; 964 } 965 if($this->IsError()) 966 $result = ""; 967 968 return $result; 969 } 970 971 /** 972 * Returns the start of a message boundary. 973 * @access private 974 */ 975 function GetBoundary($boundary, $charSet, $contentType, $encoding) { 976 $result = ""; 977 if($charSet == "") { $charSet = $this->CharSet; } 978 if($contentType == "") { $contentType = $this->ContentType; } 979 if($encoding == "") { $encoding = $this->Encoding; } 980 981 $result .= $this->TextLine("--" . $boundary); 982 $result .= sprintf("Content-Type: %s; charset = \"%s\"", 983 $contentType, $charSet); 984 $result .= $this->LE; 985 $result .= $this->HeaderLine("Content-Transfer-Encoding", $encoding); 986 $result .= $this->LE; 987 988 return $result; 989 } 990 991 /** 992 * Returns the end of a message boundary. 993 * @access private 994 */ 995 function EndBoundary($boundary) { 996 return $this->LE . "--" . $boundary . "--" . $this->LE; 997 } 998 999 /** 1000 * Sets the message type. 1001 * @access private 1002 * @return void 1003 */ 1004 function SetMessageType() { 1005 if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) 1006 $this->message_type = "plain"; 1007 else 1008 { 1009 if(count($this->attachment) > 0) 1010 $this->message_type = "attachments"; 1011 if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) 1012 $this->message_type = "alt"; 1013 if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) 1014 $this->message_type = "alt_attachments"; 1015 } 1016 } 1017 1018 /** 1019 * Returns a formatted header line. 1020 * @access private 1021 * @return string 1022 */ 1023 function HeaderLine($name, $value) { 1024 return $name . ": " . $value . $this->LE; 1025 } 1026 1027 /** 1028 * Returns a formatted mail line. 1029 * @access private 1030 * @return string 1031 */ 1032 function TextLine($value) { 1033 return $value . $this->LE; 1034 } 1035 1036 ///////////////////////////////////////////////// 1037 // ATTACHMENT METHODS 1038 ///////////////////////////////////////////////// 1039 1040 /** 1041 * Adds an attachment from a path on the filesystem. 1042 * Returns false if the file could not be found 1043 * or accessed. 1044 * @param string $path Path to the attachment. 1045 * @param string $name Overrides the attachment name. 1046 * @param string $encoding File encoding (see $Encoding). 1047 * @param string $type File extension (MIME) type. 1048 * @return bool 1049 */ 1050 function AddAttachment($path, $name = "", $encoding = "base64", 1051 $type = "application/octet-stream") { 1052 if(!@is_file($path)) 1053 { 1054 $this->SetError($this->Lang("file_access") . $path); 1055 return false; 1056 } 1057 1058 $filename = basename($path); 1059 if($name == "") 1060 $name = $filename; 1061 1062 $cur = count($this->attachment); 1063 $this->attachment[$cur][0] = $path; 1064 $this->attachment[$cur][1] = $filename; 1065 $this->attachment[$cur][2] = $name; 1066 $this->attachment[$cur][3] = $encoding; 1067 $this->attachment[$cur][4] = $type; 1068 $this->attachment[$cur][5] = false; // isStringAttachment 1069 $this->attachment[$cur][6] = "attachment"; 1070 $this->attachment[$cur][7] = 0; 1071 1072 return true; 1073 } 1074 1075 /** 1076 * Attaches all fs, string, and binary attachments to the message. 1077 * Returns an empty string on failure. 1078 * @access private 1079 * @return string 1080 */ 1081 function AttachAll() { 1082 // Return text of body 1083 $mime = array(); 1084 1085 // Add all attachments 1086 for($i = 0; $i < count($this->attachment); $i++) 1087 { 1088 // Check for string attachment 1089 $bString = $this->attachment[$i][5]; 1090 if ($bString) 1091 $string = $this->attachment[$i][0]; 1092 else 1093 $path = $this->attachment[$i][0]; 1094 1095 $filename = $this->attachment[$i][1]; 1096 $name = $this->attachment[$i][2]; 1097 $encoding = $this->attachment[$i][3]; 1098 $type = $this->attachment[$i][4]; 1099 $disposition = $this->attachment[$i][6]; 1100 $cid = $this->attachment[$i][7]; 1101 1102 $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE); 1103 $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE); 1104 $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE); 1105 1106 if($disposition == "inline") 1107 $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE); 1108 1109 $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", 1110 $disposition, $name, $this->LE.$this->LE); 1111 1112 // Encode as string attachment 1113 if($bString) 1114 { 1115 $mime[] = $this->EncodeString($string, $encoding); 1116 if($this->IsError()) { return ""; } 1117 $mime[] = $this->LE.$this->LE; 1118 } 1119 else 1120 { 1121 $mime[] = $this->EncodeFile($path, $encoding); 1122 if($this->IsError()) { return ""; } 1123 $mime[] = $this->LE.$this->LE; 1124 } 1125 } 1126 1127 $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE); 1128 1129 return join("", $mime); 1130 } 1131 1132 /** 1133 * Encodes attachment in requested format. Returns an 1134 * empty string on failure. 1135 * @access private 1136 * @return string 1137 */ 1138 function EncodeFile ($path, $encoding = "base64") { 1139 if(!@$fd = fopen($path, "rb")) 1140 { 1141 $this->SetError($this->Lang("file_open") . $path); 1142 return ""; 1143 } 1144 $magic_quotes = get_magic_quotes_runtime(); 1145 set_magic_quotes_runtime(0); 1146 $file_buffer = fread($fd, filesize($path)); 1147 $file_buffer = $this->EncodeString($file_buffer, $encoding); 1148 fclose($fd); 1149 set_magic_quotes_runtime($magic_quotes); 1150 1151 return $file_buffer; 1152 } 1153 1154 /** 1155 * Encodes string to requested format. Returns an 1156 * empty string on failure. 1157 * @access private 1158 * @return string 1159 */ 1160 function EncodeString ($str, $encoding = "base64") { 1161 $encoded = ""; 1162 switch(strtolower($encoding)) { 1163 case "base64": 1164 // chunk_split is found in PHP >= 3.0.6 1165 $encoded = chunk_split(base64_encode($str), 76, $this->LE); 1166 break; 1167 case "7bit": 1168 case "8bit": 1169 $encoded = $this->FixEOL($str); 1170 if (substr($encoded, -(strlen($this->LE))) != $this->LE) 1171 $encoded .= $this->LE; 1172 break; 1173 case "binary": 1174 $encoded = $str; 1175 break; 1176 case "quoted-printable": 1177 $encoded = $this->EncodeQP($str); 1178 break; 1179 default: 1180 $this->SetError($this->Lang("encoding") . $encoding); 1181 break; 1182 } 1183 return $encoded; 1184 } 1185 1186 /** 1187 * Encode a header string to best of Q, B, quoted or none. 1188 * @access private 1189 * @return string 1190 */ 1191 function EncodeHeader ($str, $position = 'text') { 1192 1193 /// Start Moodle Hack - do our own multibyte-safe header encoding 1194 $textlib = textlib_get_instance(); 1195 $encoded = $textlib->encode_mimeheader($str, $this->CharSet); 1196 if ($encoded !== false) { 1197 $encoded = str_replace("\n", $this->LE, $encoded); 1198 if ($position == 'phrase') { 1199 return ("\"$encoded\""); 1200 } 1201 return $encoded; 1202 } 1203 // try the old way that does not handle binary-safe line splitting in mime header 1204 /// End Moodle Hack 1205 $x = 0; 1206 1207 switch (strtolower($position)) { 1208 case 'phrase': 1209 if (!preg_match('/[\200-\377]/', $str)) { 1210 // Can't use addslashes as we don't know what value has magic_quotes_sybase. 1211 $encoded = addcslashes($str, "\0..\37\177\\\""); 1212 1213 if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) 1214 return ($encoded); 1215 else 1216 return ("\"$encoded\""); 1217 } 1218 $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); 1219 break; 1220 case 'comment': 1221 $x = preg_match_all('/[()"]/', $str, $matches); 1222 // Fall-through 1223 case 'text': 1224 default: 1225 $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); 1226 break; 1227 } 1228 1229 if ($x == 0) 1230 return ($str); 1231 1232 $maxlen = 75 - 7 - strlen($this->CharSet); 1233 // Try to select the encoding which should produce the shortest output 1234 if (strlen($str)/3 < $x) { 1235 $encoding = 'B'; 1236 $encoded = base64_encode($str); 1237 $maxlen -= $maxlen % 4; 1238 $encoded = trim(chunk_split($encoded, $maxlen, "\n")); 1239 } else { 1240 $encoding = 'Q'; 1241 $encoded = $this->EncodeQ($str, $position); 1242 $encoded = $this->WrapText($encoded, $maxlen, true); 1243 $encoded = str_replace("=".$this->LE, "\n", trim($encoded)); 1244 } 1245 1246 $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded); 1247 $encoded = trim(str_replace("\n", $this->LE, $encoded)); 1248 1249 return $encoded; 1250 } 1251 1252 /** 1253 * Encode string to quoted-printable. 1254 * @access private 1255 * @return string 1256 */ 1257 function EncodeQP ($str) { 1258 $encoded = $this->FixEOL($str); 1259 if (substr($encoded, -(strlen($this->LE))) != $this->LE) 1260 $encoded .= $this->LE; 1261 1262 // Replace every high ascii, control and = characters 1263 $encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e', 1264 "'='.sprintf('%02X', ord('\\1'))", $encoded); 1265 // Replace every spaces and tabs when it's the last character on a line 1266 $encoded = preg_replace("/([\011\040])".$this->LE."/e", 1267 "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded); 1268 1269 // Maximum line length of 76 characters before CRLF (74 + space + '=') 1270 $encoded = $this->WrapText($encoded, 74, true); 1271 1272 return $encoded; 1273 } 1274 1275 /** 1276 * Encode string to q encoding. 1277 * @access private 1278 * @return string 1279 */ 1280 function EncodeQ ($str, $position = "text") { 1281 // There should not be any EOL in the string 1282 $encoded = preg_replace("[\r\n]", "", $str); 1283 1284 switch (strtolower($position)) { 1285 case "phrase": 1286 $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); 1287 break; 1288 case "comment": 1289 $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); 1290 case "text": 1291 default: 1292 // Replace every high ascii, control =, ? and _ characters 1293 $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e', 1294 "'='.sprintf('%02X', ord('\\1'))", $encoded); 1295 break; 1296 } 1297 1298 // Replace every spaces to _ (more readable than =20) 1299 $encoded = str_replace(" ", "_", $encoded); 1300 1301 return $encoded; 1302 } 1303 1304 /** 1305 * Adds a string or binary attachment (non-filesystem) to the list. 1306 * This method can be used to attach ascii or binary data, 1307 * such as a BLOB record from a database. 1308 * @param string $string String attachment data. 1309 * @param string $filename Name of the attachment. 1310 * @param string $encoding File encoding (see $Encoding). 1311 * @param string $type File extension (MIME) type. 1312 * @return void 1313 */ 1314 function AddStringAttachment($string, $filename, $encoding = "base64", 1315 $type = "application/octet-stream") { 1316 // Append to $attachment array 1317 $cur = count($this->attachment); 1318 $this->attachment[$cur][0] = $string; 1319 $this->attachment[$cur][1] = $filename; 1320 $this->attachment[$cur][2] = $filename; 1321 $this->attachment[$cur][3] = $encoding; 1322 $this->attachment[$cur][4] = $type; 1323 $this->attachment[$cur][5] = true; // isString 1324 $this->attachment[$cur][6] = "attachment"; 1325 $this->attachment[$cur][7] = 0; 1326 } 1327 1328 /** 1329 * Adds an embedded attachment. This can include images, sounds, and 1330 * just about any other document. Make sure to set the $type to an 1331 * image type. For JPEG images use "image/jpeg" and for GIF images 1332 * use "image/gif". 1333 * @param string $path Path to the attachment. 1334 * @param string $cid Content ID of the attachment. Use this to identify 1335 * the Id for accessing the image in an HTML form. 1336 * @param string $name Overrides the attachment name. 1337 * @param string $encoding File encoding (see $Encoding). 1338 * @param string $type File extension (MIME) type. 1339 * @return bool 1340 */ 1341 function AddEmbeddedImage($path, $cid, $name = "", $encoding = "base64", 1342 $type = "application/octet-stream") { 1343 1344 if(!@is_file($path)) 1345 { 1346 $this->SetError($this->Lang("file_access") . $path); 1347 return false; 1348 } 1349 1350 $filename = basename($path); 1351 if($name == "") 1352 $name = $filename; 1353 1354 // Append to $attachment array 1355 $cur = count($this->attachment); 1356 $this->attachment[$cur][0] = $path; 1357 $this->attachment[$cur][1] = $filename; 1358 $this->attachment[$cur][2] = $name; 1359 $this->attachment[$cur][3] = $encoding; 1360 $this->attachment[$cur][4] = $type; 1361 $this->attachment[$cur][5] = false; // isStringAttachment 1362 $this->attachment[$cur][6] = "inline"; 1363 $this->attachment[$cur][7] = $cid; 1364 1365 return true; 1366 } 1367 1368 /** 1369 * Returns true if an inline attachment is present. 1370 * @access private 1371 * @return bool 1372 */ 1373 function InlineImageExists() { 1374 $result = false; 1375 for($i = 0; $i < count($this->attachment); $i++) 1376 { 1377 if($this->attachment[$i][6] == "inline") 1378 { 1379 $result = true; 1380 break; 1381 } 1382 } 1383 1384 return $result; 1385 } 1386 1387 ///////////////////////////////////////////////// 1388 // MESSAGE RESET METHODS 1389 ///////////////////////////////////////////////// 1390 1391 /** 1392 * Clears all recipients assigned in the TO array. Returns void. 1393 * @return void 1394 */ 1395 function ClearAddresses() { 1396 $this->to = array(); 1397 } 1398 1399 /** 1400 * Clears all recipients assigned in the CC array. Returns void. 1401 * @return void 1402 */ 1403 function ClearCCs() { 1404 $this->cc = array(); 1405 } 1406 1407 /** 1408 * Clears all recipients assigned in the BCC array. Returns void. 1409 * @return void 1410 */ 1411 function ClearBCCs() { 1412 $this->bcc = array(); 1413 } 1414 1415 /** 1416 * Clears all recipients assigned in the ReplyTo array. Returns void. 1417 * @return void 1418 */ 1419 function ClearReplyTos() { 1420 $this->ReplyTo = array(); 1421 } 1422 1423 /** 1424 * Clears all recipients assigned in the TO, CC and BCC 1425 * array. Returns void. 1426 * @return void 1427 */ 1428 function ClearAllRecipients() { 1429 $this->to = array(); 1430 $this->cc = array(); 1431 $this->bcc = array(); 1432 } 1433 1434 /** 1435 * Clears all previously set filesystem, string, and binary 1436 * attachments. Returns void. 1437 * @return void 1438 */ 1439 function ClearAttachments() { 1440 $this->attachment = array(); 1441 } 1442 1443 /** 1444 * Clears all custom headers. Returns void. 1445 * @return void 1446 */ 1447 function ClearCustomHeaders() { 1448 $this->CustomHeader = array(); 1449 } 1450 1451 1452 ///////////////////////////////////////////////// 1453 // MISCELLANEOUS METHODS 1454 ///////////////////////////////////////////////// 1455 1456 /** 1457 * Adds the error message to the error container. 1458 * Returns void. 1459 * @access private 1460 * @return void 1461 */ 1462 function SetError($msg) { 1463 $this->error_count++; 1464 $this->ErrorInfo = $msg; 1465 } 1466 1467 /** 1468 * Returns the proper RFC 822 formatted date. 1469 * @access private 1470 * @return string 1471 */ 1472 function RFCDate() { 1473 $tz = date("Z"); 1474 $tzs = ($tz < 0) ? "-" : "+"; 1475 $tz = abs($tz); 1476 $tz = (($tz - ($tz%3600) )/3600)*100 + ($tz%3600)/60; // moodle change - MDL-12596 1477 $result = sprintf("%s %s%04d", date("D, j M Y H:i:s"), $tzs, $tz); 1478 1479 return $result; 1480 } 1481 1482 /** 1483 * Returns the appropriate server variable. Should work with both 1484 * PHP 4.1.0+ as well as older versions. Returns an empty string 1485 * if nothing is found. 1486 * @access private 1487 * @return mixed 1488 */ 1489 function ServerVar($varName) { 1490 global $HTTP_SERVER_VARS; 1491 global $HTTP_ENV_VARS; 1492 1493 if(!isset($_SERVER)) 1494 { 1495 $_SERVER = $HTTP_SERVER_VARS; 1496 if(!isset($_SERVER["REMOTE_ADDR"])) 1497 $_SERVER = $HTTP_ENV_VARS; // must be Apache 1498 } 1499 1500 if(isset($_SERVER[$varName])) 1501 return $_SERVER[$varName]; 1502 else 1503 return ""; 1504 } 1505 1506 /** 1507 * Returns the server hostname or 'localhost.localdomain' if unknown. 1508 * @access private 1509 * @return string 1510 */ 1511 function ServerHostname() { 1512 if ($this->Hostname != "") 1513 $result = $this->Hostname; 1514 elseif ($this->ServerVar('SERVER_NAME') != "") 1515 $result = $this->ServerVar('SERVER_NAME'); 1516 else 1517 $result = "localhost.localdomain"; 1518 1519 return $result; 1520 } 1521 1522 /** 1523 * Returns a message in the appropriate language. 1524 * @access private 1525 * @return string 1526 */ 1527 function Lang($key) { 1528 if(count($this->language) < 1) 1529 $this->SetLanguage("en"); // set the default language 1530 1531 if(isset($this->language[$key])) 1532 return $this->language[$key]; 1533 else 1534 return "Language string failed to load: " . $key; 1535 } 1536 1537 /** 1538 * Returns true if an error occurred. 1539 * @return bool 1540 */ 1541 function IsError() { 1542 return ($this->error_count > 0); 1543 } 1544 1545 /** 1546 * Changes every end of line from CR or LF to CRLF. 1547 * @access private 1548 * @return string 1549 */ 1550 function FixEOL($str) { 1551 $str = str_replace("\r\n", "\n", $str); 1552 $str = str_replace("\r", "\n", $str); 1553 $str = str_replace("\n", $this->LE, $str); 1554 return $str; 1555 } 1556 1557 /** 1558 * Adds a custom header. 1559 * @return void 1560 */ 1561 function AddCustomHeader($custom_header) { 1562 $this->CustomHeader[] = explode(":", $custom_header, 2); 1563 } 1564 } 1565 1566 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |