[ Index ] |
PHP Cross Reference of vtigercrm-6.1.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /*~ class.phpmailer.php 3 .---------------------------------------------------------------------------. 4 | Software: PHPMailer - PHP email class | 5 | Version: 5.2.6 | 6 | Site: https://github.com/PHPMailer/PHPMailer/ | 7 | ------------------------------------------------------------------------- | 8 | Admins: Marcus Bointon | 9 | Admins: Jim Jagielski | 10 | Authors: Andy Prevost (codeworxtech) [email protected] | 11 | : Marcus Bointon (coolbru) [email protected] | 12 | : Jim Jagielski (jimjag) [email protected] | 13 | Founder: Brent R. Matzelle (original founder) | 14 | Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. | 15 | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. | 16 | Copyright (c) 2001-2003, Brent R. Matzelle | 17 | ------------------------------------------------------------------------- | 18 | License: Distributed under the Lesser General Public License (LGPL) | 19 | http://www.gnu.org/copyleft/lesser.html | 20 | This program is distributed in the hope that it will be useful - WITHOUT | 21 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 22 | FITNESS FOR A PARTICULAR PURPOSE. | 23 '---------------------------------------------------------------------------' 24 */ 25 26 /** 27 * PHPMailer - PHP email creation and transport class 28 * NOTE: Requires PHP version 5 or later 29 * @package PHPMailer 30 * @author Andy Prevost 31 * @author Marcus Bointon 32 * @author Jim Jagielski 33 * @copyright 2010 - 2012 Jim Jagielski 34 * @copyright 2004 - 2009 Andy Prevost 35 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 36 */ 37 38 if (version_compare(PHP_VERSION, '5.0.0', '<') ) { 39 exit("Sorry, PHPMailer will only run on PHP version 5 or greater!\n"); 40 } 41 42 /** 43 * PHP email creation and transport class 44 * @package PHPMailer 45 */ 46 class PHPMailer { 47 48 ///////////////////////////////////////////////// 49 // PROPERTIES, PUBLIC 50 ///////////////////////////////////////////////// 51 52 /** 53 * Email priority (1 = High, 3 = Normal, 5 = low). 54 * @var int 55 */ 56 public $Priority = 3; 57 58 /** 59 * Sets the CharSet of the message. 60 * @var string 61 */ 62 public $CharSet = 'UTF-8'; 63 64 /** 65 * Sets the Content-type of the message. 66 * @var string 67 */ 68 public $ContentType = 'text/plain'; 69 70 /** 71 * Sets the Encoding of the message. Options for this are 72 * "8bit", "7bit", "binary", "base64", and "quoted-printable". 73 * @var string 74 */ 75 public $Encoding = '8bit'; 76 77 /** 78 * Holds the most recent mailer error message. 79 * @var string 80 */ 81 public $ErrorInfo = ''; 82 83 /** 84 * Sets the From email address for the message. 85 * @var string 86 */ 87 public $From = 'root@localhost'; 88 89 /** 90 * Sets the From name of the message. 91 * @var string 92 */ 93 public $FromName = 'Root User'; 94 95 /** 96 * Sets the Sender email (Return-Path) of the message. 97 * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. 98 * @var string 99 */ 100 public $Sender = ''; 101 102 /** 103 * Sets the Return-Path of the message. If empty, it will 104 * be set to either From or Sender. 105 * @var string 106 */ 107 public $ReturnPath = ''; 108 109 /** 110 * Sets the Subject of the message. 111 * @var string 112 */ 113 public $Subject = ''; 114 115 /** 116 * An HTML or plain text message body. 117 * If HTML then call IsHTML(true). 118 * @var string 119 */ 120 public $Body = ''; 121 122 /** 123 * The plain-text message body. 124 * This body can be read by mail clients that do not have HTML email 125 * capability such as mutt & Eudora. 126 * Clients that can read HTML will view the normal Body. 127 * @var string 128 */ 129 public $AltBody = ''; 130 131 /** 132 * An iCal message part body 133 * Only supported in simple alt or alt_inline message types 134 * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator 135 * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/ 136 * @link http://kigkonsult.se/iCalcreator/ 137 * @var string 138 */ 139 public $Ical = ''; 140 141 /** 142 * Stores the complete compiled MIME message body. 143 * @var string 144 * @access protected 145 */ 146 protected $MIMEBody = ''; 147 148 /** 149 * Stores the complete compiled MIME message headers. 150 * @var string 151 * @access protected 152 */ 153 protected $MIMEHeader = ''; 154 155 /** 156 * Stores the extra header list which CreateHeader() doesn't fold in 157 * @var string 158 * @access protected 159 */ 160 protected $mailHeader = ''; 161 162 /** 163 * Sets word wrapping on the body of the message to a given number of 164 * characters. 165 * @var int 166 */ 167 public $WordWrap = 0; 168 169 /** 170 * Method to send mail: ("mail", "sendmail", or "smtp"). 171 * @var string 172 */ 173 public $Mailer = 'mail'; 174 175 /** 176 * Sets the path of the sendmail program. 177 * @var string 178 */ 179 public $Sendmail = '/usr/sbin/sendmail'; 180 181 /** 182 * Determine if mail() uses a fully sendmail compatible MTA that 183 * supports sendmail's "-oi -f" options 184 * @var boolean 185 */ 186 public $UseSendmailOptions = true; 187 188 /** 189 * Path to PHPMailer plugins. Useful if the SMTP class 190 * is in a different directory than the PHP include path. 191 * @var string 192 */ 193 public $PluginDir = ''; 194 195 /** 196 * Sets the email address that a reading confirmation will be sent. 197 * @var string 198 */ 199 public $ConfirmReadingTo = ''; 200 201 /** 202 * Sets the hostname to use in Message-Id and Received headers 203 * and as default HELO string. If empty, the value returned 204 * by SERVER_NAME is used or 'localhost.localdomain'. 205 * @var string 206 */ 207 public $Hostname = ''; 208 209 /** 210 * Sets the message ID to be used in the Message-Id header. 211 * If empty, a unique id will be generated. 212 * @var string 213 */ 214 public $MessageID = ''; 215 216 /** 217 * Sets the message Date to be used in the Date header. 218 * If empty, the current date will be added. 219 * @var string 220 */ 221 public $MessageDate = ''; 222 223 ///////////////////////////////////////////////// 224 // PROPERTIES FOR SMTP 225 ///////////////////////////////////////////////// 226 227 /** 228 * Sets the SMTP hosts. 229 * 230 * All hosts must be separated by a 231 * semicolon. You can also specify a different port 232 * for each host by using this format: [hostname:port] 233 * (e.g. "smtp1.example.com:25;smtp2.example.com"). 234 * Hosts will be tried in order. 235 * @var string 236 */ 237 public $Host = 'localhost'; 238 239 /** 240 * Sets the default SMTP server port. 241 * @var int 242 */ 243 public $Port = 25; 244 245 /** 246 * Sets the SMTP HELO of the message (Default is $Hostname). 247 * @var string 248 */ 249 public $Helo = ''; 250 251 /** 252 * Sets connection prefix. Options are "", "ssl" or "tls" 253 * @var string 254 */ 255 public $SMTPSecure = ''; 256 257 /** 258 * Sets SMTP authentication. Utilizes the Username and Password variables. 259 * @var bool 260 */ 261 public $SMTPAuth = false; 262 263 /** 264 * Sets SMTP username. 265 * @var string 266 */ 267 public $Username = ''; 268 269 /** 270 * Sets SMTP password. 271 * @var string 272 */ 273 public $Password = ''; 274 275 /** 276 * Sets SMTP auth type. Options are LOGIN | PLAIN | NTLM | CRAM-MD5 (default LOGIN) 277 * @var string 278 */ 279 public $AuthType = ''; 280 281 /** 282 * Sets SMTP realm. 283 * @var string 284 */ 285 public $Realm = ''; 286 287 /** 288 * Sets SMTP workstation. 289 * @var string 290 */ 291 public $Workstation = ''; 292 293 /** 294 * Sets the SMTP server timeout in seconds. 295 * This function will not work with the win32 version. 296 * @var int 297 */ 298 public $Timeout = 10; 299 300 /** 301 * Sets SMTP class debugging on or off. 302 * @var bool 303 */ 304 public $SMTPDebug = false; 305 306 /** 307 * Sets the function/method to use for debugging output. 308 * Right now we only honor "echo" or "error_log" 309 * @var string 310 */ 311 public $Debugoutput = "echo"; 312 313 /** 314 * Prevents the SMTP connection from being closed after each mail 315 * sending. If this is set to true then to close the connection 316 * requires an explicit call to SmtpClose(). 317 * @var bool 318 */ 319 public $SMTPKeepAlive = false; 320 321 /** 322 * Provides the ability to have the TO field process individual 323 * emails, instead of sending to entire TO addresses 324 * @var bool 325 */ 326 public $SingleTo = false; 327 328 /** 329 * Should we generate VERP addresses when sending via SMTP? 330 * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path 331 * @var bool 332 */ 333 public $do_verp = false; 334 335 /** 336 * If SingleTo is true, this provides the array to hold the email addresses 337 * @var bool 338 */ 339 public $SingleToArray = array(); 340 341 /** 342 * Should we allow sending messages with empty body? 343 * @var bool 344 */ 345 public $AllowEmpty = false; 346 347 /** 348 * Provides the ability to change the generic line ending 349 * NOTE: The default remains '\n'. We force CRLF where we KNOW 350 * it must be used via self::CRLF 351 * @var string 352 */ 353 public $LE = "\n"; 354 355 /** 356 * Used with DKIM Signing 357 * required parameter if DKIM is enabled 358 * 359 * domain selector example domainkey 360 * @var string 361 */ 362 public $DKIM_selector = ''; 363 364 /** 365 * Used with DKIM Signing 366 * required if DKIM is enabled, in format of email address '[email protected]' typically used as the source of the email 367 * @var string 368 */ 369 public $DKIM_identity = ''; 370 371 /** 372 * Used with DKIM Signing 373 * optional parameter if your private key requires a passphras 374 * @var string 375 */ 376 public $DKIM_passphrase = ''; 377 378 /** 379 * Used with DKIM Singing 380 * required if DKIM is enabled, in format of email address 'domain.com' 381 * @var string 382 */ 383 public $DKIM_domain = ''; 384 385 /** 386 * Used with DKIM Signing 387 * required if DKIM is enabled, path to private key file 388 * @var string 389 */ 390 public $DKIM_private = ''; 391 392 /** 393 * Callback Action function name. 394 * The function that handles the result of the send email action. 395 * It is called out by Send() for each email sent. 396 * 397 * Value can be: 398 * - 'function_name' for function names 399 * - 'Class::Method' for static method calls 400 * - array($object, 'Method') for calling methods on $object 401 * See http://php.net/is_callable manual page for more details. 402 * 403 * Parameters: 404 * bool $result result of the send action 405 * string $to email address of the recipient 406 * string $cc cc email addresses 407 * string $bcc bcc email addresses 408 * string $subject the subject 409 * string $body the email body 410 * string $from email address of sender 411 * @var string 412 */ 413 public $action_function = ''; //'callbackAction'; 414 415 /** 416 * Sets the PHPMailer Version number 417 * @var string 418 */ 419 public $Version = '5.2.6'; 420 421 /** 422 * What to use in the X-Mailer header 423 * @var string NULL for default, whitespace for None, or actual string to use 424 */ 425 public $XMailer = ''; 426 427 ///////////////////////////////////////////////// 428 // PROPERTIES, PRIVATE AND PROTECTED 429 ///////////////////////////////////////////////// 430 431 /** 432 * @var SMTP An instance of the SMTP sender class 433 * @access protected 434 */ 435 public $smtp = null; 436 /** 437 * @var array An array of 'to' addresses 438 * @access protected 439 */ 440 public $to = array(); 441 /** 442 * @var array An array of 'cc' addresses 443 * @access protected 444 */ 445 public $cc = array(); 446 /** 447 * @var array An array of 'bcc' addresses 448 * @access protected 449 */ 450 public $bcc = array(); 451 /** 452 * @var array An array of reply-to name and address 453 * @access protected 454 */ 455 public $ReplyTo = array(); 456 /** 457 * @var array An array of all kinds of addresses: to, cc, bcc, replyto 458 * @access protected 459 */ 460 protected $all_recipients = array(); 461 /** 462 * @var array An array of attachments 463 * @access protected 464 */ 465 public $attachment = array(); 466 /** 467 * @var array An array of custom headers 468 * @access protected 469 */ 470 protected $CustomHeader = array(); 471 /** 472 * @var string The message's MIME type 473 * @access protected 474 */ 475 protected $message_type = ''; 476 /** 477 * @var array An array of MIME boundary strings 478 * @access protected 479 */ 480 protected $boundary = array(); 481 /** 482 * @var array An array of available languages 483 * @access protected 484 */ 485 public $language = array(); 486 /** 487 * @var integer The number of errors encountered 488 * @access protected 489 */ 490 protected $error_count = 0; 491 /** 492 * @var string The filename of a DKIM certificate file 493 * @access protected 494 */ 495 protected $sign_cert_file = ''; 496 /** 497 * @var string The filename of a DKIM key file 498 * @access protected 499 */ 500 protected $sign_key_file = ''; 501 /** 502 * @var string The password of a DKIM key 503 * @access protected 504 */ 505 protected $sign_key_pass = ''; 506 /** 507 * @var boolean Whether to throw exceptions for errors 508 * @access protected 509 */ 510 protected $exceptions = false; 511 512 ///////////////////////////////////////////////// 513 // CONSTANTS 514 ///////////////////////////////////////////////// 515 516 const STOP_MESSAGE = 0; // message only, continue processing 517 const STOP_CONTINUE = 1; // message?, likely ok to continue processing 518 const STOP_CRITICAL = 2; // message, plus full stop, critical error reached 519 const CRLF = "\r\n"; // SMTP RFC specified EOL 520 521 ///////////////////////////////////////////////// 522 // METHODS, VARIABLES 523 ///////////////////////////////////////////////// 524 525 /** 526 * Calls actual mail() function, but in a safe_mode aware fashion 527 * Also, unless sendmail_path points to sendmail (or something that 528 * claims to be sendmail), don't pass params (not a perfect fix, 529 * but it will do) 530 * @param string $to To 531 * @param string $subject Subject 532 * @param string $body Message Body 533 * @param string $header Additional Header(s) 534 * @param string $params Params 535 * @access private 536 * @return bool 537 */ 538 private function mail_passthru($to, $subject, $body, $header, $params) { 539 if ( ini_get('safe_mode') || !($this->UseSendmailOptions) ) { 540 $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header); 541 } else { 542 $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header, $params); 543 } 544 return $rt; 545 } 546 547 /** 548 * Outputs debugging info via user-defined method 549 * @param string $str 550 */ 551 protected function edebug($str) { 552 switch ($this->Debugoutput) { 553 case 'error_log': 554 error_log($str); 555 break; 556 case 'html': 557 //Cleans up output a bit for a better looking display that's HTML-safe 558 echo htmlentities(preg_replace('/[\r\n]+/', '', $str), ENT_QUOTES, $this->CharSet)."<br>\n"; 559 break; 560 case 'echo': 561 default: 562 //Just echoes exactly what was received 563 echo $str; 564 } 565 } 566 567 /** 568 * Constructor 569 * @param boolean $exceptions Should we throw external exceptions? 570 */ 571 public function __construct($exceptions = false) { 572 $this->exceptions = ($exceptions == true); 573 } 574 575 /** 576 * Destructor 577 */ 578 public function __destruct() { 579 if ($this->Mailer == 'smtp') { //Close any open SMTP connection nicely 580 $this->SmtpClose(); 581 } 582 } 583 584 /** 585 * Sets message type to HTML. 586 * @param bool $ishtml 587 * @return void 588 */ 589 public function IsHTML($ishtml = true) { 590 if ($ishtml) { 591 $this->ContentType = 'text/html'; 592 } else { 593 $this->ContentType = 'text/plain'; 594 } 595 } 596 597 /** 598 * Sets Mailer to send message using SMTP. 599 * @return void 600 */ 601 public function IsSMTP() { 602 $this->Mailer = 'smtp'; 603 } 604 605 /** 606 * Sets Mailer to send message using PHP mail() function. 607 * @return void 608 */ 609 public function IsMail() { 610 $this->Mailer = 'mail'; 611 } 612 613 /** 614 * Sets Mailer to send message using the $Sendmail program. 615 * @return void 616 */ 617 public function IsSendmail() { 618 if (!stristr(ini_get('sendmail_path'), 'sendmail')) { 619 $this->Sendmail = '/var/qmail/bin/sendmail'; 620 } 621 $this->Mailer = 'sendmail'; 622 } 623 624 /** 625 * Sets Mailer to send message using the qmail MTA. 626 * @return void 627 */ 628 public function IsQmail() { 629 if (stristr(ini_get('sendmail_path'), 'qmail')) { 630 $this->Sendmail = '/var/qmail/bin/sendmail'; 631 } 632 $this->Mailer = 'sendmail'; 633 } 634 635 ///////////////////////////////////////////////// 636 // METHODS, RECIPIENTS 637 ///////////////////////////////////////////////// 638 639 /** 640 * Adds a "To" address. 641 * @param string $address 642 * @param string $name 643 * @return boolean true on success, false if address already used 644 */ 645 public function AddAddress($address, $name = '') { 646 return $this->AddAnAddress('to', $address, $name); 647 } 648 649 /** 650 * Adds a "Cc" address. 651 * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer. 652 * @param string $address 653 * @param string $name 654 * @return boolean true on success, false if address already used 655 */ 656 public function AddCC($address, $name = '') { 657 return $this->AddAnAddress('cc', $address, $name); 658 } 659 660 /** 661 * Adds a "Bcc" address. 662 * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer. 663 * @param string $address 664 * @param string $name 665 * @return boolean true on success, false if address already used 666 */ 667 public function AddBCC($address, $name = '') { 668 return $this->AddAnAddress('bcc', $address, $name); 669 } 670 671 /** 672 * Adds a "Reply-to" address. 673 * @param string $address 674 * @param string $name 675 * @return boolean 676 */ 677 public function AddReplyTo($address, $name = '') { 678 return $this->AddAnAddress('Reply-To', $address, $name); 679 } 680 681 /** 682 * Adds an address to one of the recipient arrays 683 * Addresses that have been added already return false, but do not throw exceptions 684 * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo' 685 * @param string $address The email address to send to 686 * @param string $name 687 * @throws phpmailerException 688 * @return boolean true on success, false if address already used or invalid in some way 689 * @access protected 690 */ 691 protected function AddAnAddress($kind, $address, $name = '') { 692 if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) { 693 $this->SetError($this->Lang('Invalid recipient array').': '.$kind); 694 if ($this->exceptions) { 695 throw new phpmailerException('Invalid recipient array: ' . $kind); 696 } 697 if ($this->SMTPDebug) { 698 $this->edebug($this->Lang('Invalid recipient array').': '.$kind); 699 } 700 return false; 701 } 702 $address = trim($address); 703 704 $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim 705 if (!$this->ValidateAddress($address)) { 706 $this->SetError($this->Lang('invalid_address').': '. $address); 707 if ($this->exceptions) { 708 throw new phpmailerException($this->Lang('invalid_address').': '.$address); 709 } 710 if ($this->SMTPDebug) { 711 $this->edebug($this->Lang('invalid_address').': '.$address); 712 } 713 return false; 714 } 715 if ($kind != 'Reply-To') { 716 if (!isset($this->all_recipients[strtolower($address)])) { 717 array_push($this->$kind, array($address, $name)); 718 $this->all_recipients[strtolower($address)] = true; 719 return true; 720 } 721 } else { 722 if (!array_key_exists(strtolower($address), $this->ReplyTo)) { 723 $this->ReplyTo[strtolower($address)] = array($address, $name); 724 return true; 725 } 726 } 727 return false; 728 } 729 730 /** 731 * Set the From and FromName properties 732 * @param string $address 733 * @param string $name 734 * @param boolean $auto Whether to also set the Sender address, defaults to true 735 * @throws phpmailerException 736 * @return boolean 737 */ 738 public function SetFrom($address, $name = '', $auto = true) { 739 $address = trim($address); 740 $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim 741 if (!$this->ValidateAddress($address)) { 742 $this->SetError($this->Lang('invalid_address').': '. $address); 743 if ($this->exceptions) { 744 throw new phpmailerException($this->Lang('invalid_address').': '.$address); 745 } 746 if ($this->SMTPDebug) { 747 $this->edebug($this->Lang('invalid_address').': '.$address); 748 } 749 return false; 750 } 751 $this->From = $address; 752 $this->FromName = $name; 753 if ($auto) { 754 if (empty($this->Sender)) { 755 $this->Sender = $address; 756 } 757 } 758 return true; 759 } 760 761 /** 762 * Check that a string looks roughly like an email address should 763 * Static so it can be used without instantiation, public so people can overload 764 * Conforms to RFC5322: Uses *correct* regex on which FILTER_VALIDATE_EMAIL is 765 * based; So why not use FILTER_VALIDATE_EMAIL? Because it was broken to 766 * not allow a@b type valid addresses :( 767 * @link http://squiloople.com/2009/12/20/email-address-validation/ 768 * @copyright regex Copyright Michael Rushton 2009-10 | http://squiloople.com/ | Feel free to use and redistribute this code. But please keep this copyright notice. 769 * @param string $address The email address to check 770 * @return boolean 771 * @static 772 * @access public 773 */ 774 public static function ValidateAddress($address) { 775 if (defined('PCRE_VERSION')) { //Check this instead of extension_loaded so it works when that function is disabled 776 if (version_compare(PCRE_VERSION, '8.0') >= 0) { 777 return (boolean)preg_match('/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', $address); 778 } else { 779 //Fall back to an older regex that doesn't need a recent PCRE 780 return (boolean)preg_match('/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD', $address); 781 } 782 } else { 783 //No PCRE! Do something _very_ approximate! 784 //Check the address is 3 chars or longer and contains an @ that's not the first or last char 785 return (strlen($address) >= 3 and strpos($address, '@') >= 1 and strpos($address, '@') != strlen($address) - 1); 786 } 787 } 788 789 ///////////////////////////////////////////////// 790 // METHODS, MAIL SENDING 791 ///////////////////////////////////////////////// 792 793 /** 794 * Creates message and assigns Mailer. If the message is 795 * not sent successfully then it returns false. Use the ErrorInfo 796 * variable to view description of the error. 797 * @throws phpmailerException 798 * @return bool 799 */ 800 public function Send() { 801 try { 802 if(!$this->PreSend()) return false; 803 return $this->PostSend(); 804 } catch (phpmailerException $e) { 805 $this->mailHeader = ''; 806 $this->SetError($e->getMessage()); 807 if ($this->exceptions) { 808 throw $e; 809 } 810 return false; 811 } 812 } 813 814 /** 815 * Prep mail by constructing all message entities 816 * @throws phpmailerException 817 * @return bool 818 */ 819 public function PreSend() { 820 try { 821 $this->mailHeader = ""; 822 if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) { 823 throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL); 824 } 825 // Set whether the message is multipart/alternative 826 if(!empty($this->AltBody)) { 827 $this->ContentType = 'multipart/alternative'; 828 } 829 830 $this->error_count = 0; // reset errors 831 $this->SetMessageType(); 832 //Refuse to send an empty message unless we are specifically allowing it 833 if (!$this->AllowEmpty and empty($this->Body)) { 834 throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL); 835 } 836 837 $this->MIMEHeader = $this->CreateHeader(); 838 $this->MIMEBody = $this->CreateBody(); 839 // an extra header list which CreateHeader() doesn't fold in 840 if ($this->Mailer == 'mail') { 841 if (count($this->to) > 0) { 842 $this->mailHeader .= $this->AddrAppend("To", $this->to); 843 } else { 844 $this->mailHeader .= $this->HeaderLine("To", "undisclosed-recipients:;"); 845 } 846 $this->mailHeader .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader(trim($this->Subject)))); 847 } 848 849 // digitally sign with DKIM if enabled 850 if (!empty($this->DKIM_domain) && !empty($this->DKIM_private) && !empty($this->DKIM_selector) && !empty($this->DKIM_domain) && file_exists($this->DKIM_private)) { 851 $header_dkim = $this->DKIM_Add($this->MIMEHeader . $this->mailHeader, $this->EncodeHeader($this->SecureHeader($this->Subject)), $this->MIMEBody); 852 $this->MIMEHeader = str_replace("\r\n", "\n", $header_dkim) . $this->MIMEHeader; 853 } 854 855 return true; 856 857 } catch (phpmailerException $e) { 858 $this->SetError($e->getMessage()); 859 if ($this->exceptions) { 860 throw $e; 861 } 862 return false; 863 } 864 } 865 866 /** 867 * Actual Email transport function 868 * Send the email via the selected mechanism 869 * @throws phpmailerException 870 * @return bool 871 */ 872 public function PostSend() { 873 try { 874 // Choose the mailer and send through it 875 switch($this->Mailer) { 876 case 'sendmail': 877 return $this->SendmailSend($this->MIMEHeader, $this->MIMEBody); 878 case 'smtp': 879 return $this->SmtpSend($this->MIMEHeader, $this->MIMEBody); 880 case 'mail': 881 return $this->MailSend($this->MIMEHeader, $this->MIMEBody); 882 default: 883 return $this->MailSend($this->MIMEHeader, $this->MIMEBody); 884 } 885 } catch (phpmailerException $e) { 886 $this->SetError($e->getMessage()); 887 if ($this->exceptions) { 888 throw $e; 889 } 890 if ($this->SMTPDebug) { 891 $this->edebug($e->getMessage()."\n"); 892 } 893 } 894 return false; 895 } 896 897 /** 898 * Sends mail using the $Sendmail program. 899 * @param string $header The message headers 900 * @param string $body The message body 901 * @throws phpmailerException 902 * @access protected 903 * @return bool 904 */ 905 protected function SendmailSend($header, $body) { 906 if ($this->Sender != '') { 907 $sendmail = sprintf("%s -oi -f%s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); 908 } else { 909 $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail)); 910 } 911 if ($this->SingleTo === true) { 912 foreach ($this->SingleToArray as $val) { 913 if(!@$mail = popen($sendmail, 'w')) { 914 throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); 915 } 916 fputs($mail, "To: " . $val . "\n"); 917 fputs($mail, $header); 918 fputs($mail, $body); 919 $result = pclose($mail); 920 // implement call back function if it exists 921 $isSent = ($result == 0) ? 1 : 0; 922 $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body); 923 if($result != 0) { 924 throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); 925 } 926 } 927 } else { 928 if(!@$mail = popen($sendmail, 'w')) { 929 throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); 930 } 931 fputs($mail, $header); 932 fputs($mail, $body); 933 $result = pclose($mail); 934 // implement call back function if it exists 935 $isSent = ($result == 0) ? 1 : 0; 936 $this->doCallback($isSent, $this->to, $this->cc, $this->bcc, $this->Subject, $body); 937 if($result != 0) { 938 throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); 939 } 940 } 941 return true; 942 } 943 944 /** 945 * Sends mail using the PHP mail() function. 946 * @param string $header The message headers 947 * @param string $body The message body 948 * @throws phpmailerException 949 * @access protected 950 * @return bool 951 */ 952 protected function MailSend($header, $body) { 953 $toArr = array(); 954 foreach($this->to as $t) { 955 $toArr[] = $this->AddrFormat($t); 956 } 957 $to = implode(', ', $toArr); 958 959 if (empty($this->Sender)) { 960 $params = " "; 961 } else { 962 $params = sprintf("-f%s", $this->Sender); 963 } 964 if ($this->Sender != '' and !ini_get('safe_mode')) { 965 $old_from = ini_get('sendmail_from'); 966 ini_set('sendmail_from', $this->Sender); 967 } 968 $rt = false; 969 if ($this->SingleTo === true && count($toArr) > 1) { 970 foreach ($toArr as $val) { 971 $rt = $this->mail_passthru($val, $this->Subject, $body, $header, $params); 972 // implement call back function if it exists 973 $isSent = ($rt == 1) ? 1 : 0; 974 $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body); 975 } 976 } else { 977 $rt = $this->mail_passthru($to, $this->Subject, $body, $header, $params); 978 // implement call back function if it exists 979 $isSent = ($rt == 1) ? 1 : 0; 980 $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body); 981 } 982 if (isset($old_from)) { 983 ini_set('sendmail_from', $old_from); 984 } 985 if(!$rt) { 986 throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL); 987 } 988 return true; 989 } 990 991 /** 992 * Sends mail via SMTP using PhpSMTP 993 * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. 994 * @param string $header The message headers 995 * @param string $body The message body 996 * @throws phpmailerException 997 * @uses SMTP 998 * @access protected 999 * @return bool 1000 */ 1001 protected function SmtpSend($header, $body) { 1002 require_once $this->PluginDir . 'class.smtp.php'; 1003 $bad_rcpt = array(); 1004 1005 if(!$this->SmtpConnect()) { 1006 throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL); 1007 } 1008 $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender; 1009 if(!$this->smtp->Mail($smtp_from)) { 1010 $this->SetError($this->Lang('from_failed') . $smtp_from . ' : ' .implode(',', $this->smtp->getError())); 1011 throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL); 1012 } 1013 1014 // Attempt to send attach all recipients 1015 foreach($this->to as $to) { 1016 if (!$this->smtp->Recipient($to[0])) { 1017 $bad_rcpt[] = $to[0]; 1018 // implement call back function if it exists 1019 $isSent = 0; 1020 $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body); 1021 } else { 1022 // implement call back function if it exists 1023 $isSent = 1; 1024 $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body); 1025 } 1026 } 1027 foreach($this->cc as $cc) { 1028 if (!$this->smtp->Recipient($cc[0])) { 1029 $bad_rcpt[] = $cc[0]; 1030 // implement call back function if it exists 1031 $isSent = 0; 1032 $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body); 1033 } else { 1034 // implement call back function if it exists 1035 $isSent = 1; 1036 $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body); 1037 } 1038 } 1039 foreach($this->bcc as $bcc) { 1040 if (!$this->smtp->Recipient($bcc[0])) { 1041 $bad_rcpt[] = $bcc[0]; 1042 // implement call back function if it exists 1043 $isSent = 0; 1044 $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body); 1045 } else { 1046 // implement call back function if it exists 1047 $isSent = 1; 1048 $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body); 1049 } 1050 } 1051 1052 1053 if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses 1054 $badaddresses = implode(', ', $bad_rcpt); 1055 throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses); 1056 } 1057 if(!$this->smtp->Data($header . $body)) { 1058 throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL); 1059 } 1060 if($this->SMTPKeepAlive == true) { 1061 $this->smtp->Reset(); 1062 } else { 1063 $this->smtp->Quit(); 1064 $this->smtp->Close(); 1065 } 1066 return true; 1067 } 1068 1069 /** 1070 * Initiates a connection to an SMTP server. 1071 * Returns false if the operation failed. 1072 * @param array $options An array of options compatible with stream_context_create() 1073 * @uses SMTP 1074 * @access public 1075 * @throws phpmailerException 1076 * @return bool 1077 */ 1078 public function SmtpConnect($options = array()) { 1079 if(is_null($this->smtp)) { 1080 $this->smtp = new SMTP; 1081 } 1082 1083 //Already connected? 1084 if ($this->smtp->Connected()) { 1085 return true; 1086 } 1087 1088 $this->smtp->Timeout = $this->Timeout; 1089 $this->smtp->do_debug = $this->SMTPDebug; 1090 $this->smtp->Debugoutput = $this->Debugoutput; 1091 $this->smtp->do_verp = $this->do_verp; 1092 $index = 0; 1093 $tls = ($this->SMTPSecure == 'tls'); 1094 $ssl = ($this->SMTPSecure == 'ssl'); 1095 $hosts = explode(';', $this->Host); 1096 $lastexception = null; 1097 1098 foreach ($hosts as $hostentry) { 1099 $hostinfo = array(); 1100 $host = $hostentry; 1101 $port = $this->Port; 1102 if (preg_match('/^(.+):([0-9]+)$/', $hostentry, $hostinfo)) { //If $hostentry contains 'address:port', override default 1103 $host = $hostinfo[1]; 1104 $port = $hostinfo[2]; 1105 } 1106 if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout, $options)) { 1107 try { 1108 if ($this->Helo) { 1109 $hello = $this->Helo; 1110 } else { 1111 $hello = $this->ServerHostname(); 1112 } 1113 $this->smtp->Hello($hello); 1114 1115 if ($tls) { 1116 if (!$this->smtp->StartTLS()) { 1117 throw new phpmailerException($this->Lang('connect_host')); 1118 } 1119 //We must resend HELO after tls negotiation 1120 $this->smtp->Hello($hello); 1121 } 1122 if ($this->SMTPAuth) { 1123 if (!$this->smtp->Authenticate($this->Username, $this->Password, $this->AuthType, $this->Realm, $this->Workstation)) { 1124 throw new phpmailerException($this->Lang('authenticate')); 1125 } 1126 } 1127 return true; 1128 } catch (phpmailerException $e) { 1129 $lastexception = $e; 1130 //We must have connected, but then failed TLS or Auth, so close connection nicely 1131 $this->smtp->Quit(); 1132 } 1133 } 1134 } 1135 //If we get here, all connection attempts have failed, so close connection hard 1136 $this->smtp->Close(); 1137 //As we've caught all exceptions, just report whatever the last one was 1138 if ($this->exceptions and !is_null($lastexception)) { 1139 throw $lastexception; 1140 } 1141 return false; 1142 } 1143 1144 /** 1145 * Closes the active SMTP session if one exists. 1146 * @return void 1147 */ 1148 public function SmtpClose() { 1149 if ($this->smtp !== null) { 1150 if($this->smtp->Connected()) { 1151 $this->smtp->Quit(); 1152 $this->smtp->Close(); 1153 } 1154 } 1155 } 1156 1157 /** 1158 * Sets the language for all class error messages. 1159 * Returns false if it cannot load the language file. The default language is English. 1160 * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br") 1161 * @param string $lang_path Path to the language file directory 1162 * @return bool 1163 * @access public 1164 */ 1165 function SetLanguage($langcode = 'en', $lang_path = 'language/') { 1166 //Define full set of translatable strings 1167 $PHPMAILER_LANG = array( 1168 'authenticate' => 'SMTP Error: Could not authenticate.', 1169 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', 1170 'data_not_accepted' => 'SMTP Error: Data not accepted.', 1171 'empty_message' => 'Message body empty', 1172 'encoding' => 'Unknown encoding: ', 1173 'execute' => 'Could not execute: ', 1174 'file_access' => 'Could not access file: ', 1175 'file_open' => 'File Error: Could not open file: ', 1176 'from_failed' => 'The following From address failed: ', 1177 'instantiate' => 'Could not instantiate mail function.', 1178 'invalid_address' => 'Invalid address', 1179 'mailer_not_supported' => ' mailer is not supported.', 1180 'provide_address' => 'You must provide at least one recipient email address.', 1181 'recipients_failed' => 'SMTP Error: The following recipients failed: ', 1182 'signing' => 'Signing Error: ', 1183 'smtp_connect_failed' => 'SMTP Connect() failed.', 1184 'smtp_error' => 'SMTP server error: ', 1185 'variable_set' => 'Cannot set or reset variable: ' 1186 ); 1187 //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"! 1188 $l = true; 1189 if ($langcode != 'en') { //There is no English translation file 1190 $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php'; 1191 } 1192 $this->language = $PHPMAILER_LANG; 1193 return ($l == true); //Returns false if language not found 1194 } 1195 1196 /** 1197 * Return the current array of language strings 1198 * @return array 1199 */ 1200 public function GetTranslations() { 1201 return $this->language; 1202 } 1203 1204 ///////////////////////////////////////////////// 1205 // METHODS, MESSAGE CREATION 1206 ///////////////////////////////////////////////// 1207 1208 /** 1209 * Creates recipient headers. 1210 * @access public 1211 * @param string $type 1212 * @param array $addr 1213 * @return string 1214 */ 1215 public function AddrAppend($type, $addr) { 1216 $addr_str = $type . ': '; 1217 $addresses = array(); 1218 foreach ($addr as $a) { 1219 $addresses[] = $this->AddrFormat($a); 1220 } 1221 $addr_str .= implode(', ', $addresses); 1222 $addr_str .= $this->LE; 1223 1224 return $addr_str; 1225 } 1226 1227 /** 1228 * Formats an address correctly. 1229 * @access public 1230 * @param string $addr 1231 * @return string 1232 */ 1233 public function AddrFormat($addr) { 1234 if (empty($addr[1])) { 1235 return $this->SecureHeader($addr[0]); 1236 } else { 1237 return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">"; 1238 } 1239 } 1240 1241 /** 1242 * Wraps message for use with mailers that do not 1243 * automatically perform wrapping and for quoted-printable. 1244 * Original written by philippe. 1245 * @param string $message The message to wrap 1246 * @param integer $length The line length to wrap to 1247 * @param boolean $qp_mode Whether to run in Quoted-Printable mode 1248 * @access public 1249 * @return string 1250 */ 1251 public function WrapText($message, $length, $qp_mode = false) { 1252 $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE; 1253 // If utf-8 encoding is used, we will need to make sure we don't 1254 // split multibyte characters when we wrap 1255 $is_utf8 = (strtolower($this->CharSet) == "utf-8"); 1256 $lelen = strlen($this->LE); 1257 $crlflen = strlen(self::CRLF); 1258 1259 $message = $this->FixEOL($message); 1260 if (substr($message, -$lelen) == $this->LE) { 1261 $message = substr($message, 0, -$lelen); 1262 } 1263 1264 $line = explode($this->LE, $message); // Magic. We know FixEOL uses $LE 1265 $message = ''; 1266 for ($i = 0 ;$i < count($line); $i++) { 1267 $line_part = explode(' ', $line[$i]); 1268 $buf = ''; 1269 for ($e = 0; $e<count($line_part); $e++) { 1270 $word = $line_part[$e]; 1271 if ($qp_mode and (strlen($word) > $length)) { 1272 $space_left = $length - strlen($buf) - $crlflen; 1273 if ($e != 0) { 1274 if ($space_left > 20) { 1275 $len = $space_left; 1276 if ($is_utf8) { 1277 $len = $this->UTF8CharBoundary($word, $len); 1278 } elseif (substr($word, $len - 1, 1) == "=") { 1279 $len--; 1280 } elseif (substr($word, $len - 2, 1) == "=") { 1281 $len -= 2; 1282 } 1283 $part = substr($word, 0, $len); 1284 $word = substr($word, $len); 1285 $buf .= ' ' . $part; 1286 $message .= $buf . sprintf("=%s", self::CRLF); 1287 } else { 1288 $message .= $buf . $soft_break; 1289 } 1290 $buf = ''; 1291 } 1292 while (strlen($word) > 0) { 1293 if ($length <= 0) { 1294 break; 1295 } 1296 $len = $length; 1297 if ($is_utf8) { 1298 $len = $this->UTF8CharBoundary($word, $len); 1299 } elseif (substr($word, $len - 1, 1) == "=") { 1300 $len--; 1301 } elseif (substr($word, $len - 2, 1) == "=") { 1302 $len -= 2; 1303 } 1304 $part = substr($word, 0, $len); 1305 $word = substr($word, $len); 1306 1307 if (strlen($word) > 0) { 1308 $message .= $part . sprintf("=%s", self::CRLF); 1309 } else { 1310 $buf = $part; 1311 } 1312 } 1313 } else { 1314 $buf_o = $buf; 1315 $buf .= ($e == 0) ? $word : (' ' . $word); 1316 1317 if (strlen($buf) > $length and $buf_o != '') { 1318 $message .= $buf_o . $soft_break; 1319 $buf = $word; 1320 } 1321 } 1322 } 1323 $message .= $buf . self::CRLF; 1324 } 1325 1326 return $message; 1327 } 1328 1329 /** 1330 * Finds last character boundary prior to maxLength in a utf-8 1331 * quoted (printable) encoded string. 1332 * Original written by Colin Brown. 1333 * @access public 1334 * @param string $encodedText utf-8 QP text 1335 * @param int $maxLength find last character boundary prior to this length 1336 * @return int 1337 */ 1338 public function UTF8CharBoundary($encodedText, $maxLength) { 1339 $foundSplitPos = false; 1340 $lookBack = 3; 1341 while (!$foundSplitPos) { 1342 $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); 1343 $encodedCharPos = strpos($lastChunk, "="); 1344 if ($encodedCharPos !== false) { 1345 // Found start of encoded character byte within $lookBack block. 1346 // Check the encoded byte value (the 2 chars after the '=') 1347 $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); 1348 $dec = hexdec($hex); 1349 if ($dec < 128) { // Single byte character. 1350 // If the encoded char was found at pos 0, it will fit 1351 // otherwise reduce maxLength to start of the encoded char 1352 $maxLength = ($encodedCharPos == 0) ? $maxLength : 1353 $maxLength - ($lookBack - $encodedCharPos); 1354 $foundSplitPos = true; 1355 } elseif ($dec >= 192) { // First byte of a multi byte character 1356 // Reduce maxLength to split at start of character 1357 $maxLength = $maxLength - ($lookBack - $encodedCharPos); 1358 $foundSplitPos = true; 1359 } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back 1360 $lookBack += 3; 1361 } 1362 } else { 1363 // No encoded character found 1364 $foundSplitPos = true; 1365 } 1366 } 1367 return $maxLength; 1368 } 1369 1370 1371 /** 1372 * Set the body wrapping. 1373 * @access public 1374 * @return void 1375 */ 1376 public function SetWordWrap() { 1377 if($this->WordWrap < 1) { 1378 return; 1379 } 1380 1381 switch($this->message_type) { 1382 case 'alt': 1383 case 'alt_inline': 1384 case 'alt_attach': 1385 case 'alt_inline_attach': 1386 $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap); 1387 break; 1388 default: 1389 $this->Body = $this->WrapText($this->Body, $this->WordWrap); 1390 break; 1391 } 1392 } 1393 1394 /** 1395 * Assembles message header. 1396 * @access public 1397 * @return string The assembled header 1398 */ 1399 public function CreateHeader() { 1400 $result = ''; 1401 1402 // Set the boundaries 1403 $uniq_id = md5(uniqid(time())); 1404 $this->boundary[1] = 'b1_' . $uniq_id; 1405 $this->boundary[2] = 'b2_' . $uniq_id; 1406 $this->boundary[3] = 'b3_' . $uniq_id; 1407 1408 if ($this->MessageDate == '') { 1409 $result .= $this->HeaderLine('Date', self::RFCDate()); 1410 } else { 1411 $result .= $this->HeaderLine('Date', $this->MessageDate); 1412 } 1413 1414 if ($this->ReturnPath) { 1415 $result .= $this->HeaderLine('Return-Path', '<'.trim($this->ReturnPath).'>'); 1416 } elseif ($this->Sender == '') { 1417 $result .= $this->HeaderLine('Return-Path', '<'.trim($this->From).'>'); 1418 } else { 1419 $result .= $this->HeaderLine('Return-Path', '<'.trim($this->Sender).'>'); 1420 } 1421 1422 // To be created automatically by mail() 1423 if($this->Mailer != 'mail') { 1424 if ($this->SingleTo === true) { 1425 foreach($this->to as $t) { 1426 $this->SingleToArray[] = $this->AddrFormat($t); 1427 } 1428 } else { 1429 if(count($this->to) > 0) { 1430 $result .= $this->AddrAppend('To', $this->to); 1431 } elseif (count($this->cc) == 0) { 1432 $result .= $this->HeaderLine('To', 'undisclosed-recipients:;'); 1433 } 1434 } 1435 } 1436 1437 $from = array(); 1438 $from[0][0] = trim($this->From); 1439 $from[0][1] = $this->FromName; 1440 $result .= $this->AddrAppend('From', $from); 1441 1442 // sendmail and mail() extract Cc from the header before sending 1443 if(count($this->cc) > 0) { 1444 $result .= $this->AddrAppend('Cc', $this->cc); 1445 } 1446 1447 // sendmail and mail() extract Bcc from the header before sending 1448 if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) { 1449 $result .= $this->AddrAppend('Bcc', $this->bcc); 1450 } 1451 1452 if(count($this->ReplyTo) > 0) { 1453 $result .= $this->AddrAppend('Reply-To', $this->ReplyTo); 1454 } 1455 1456 // mail() sets the subject itself 1457 if($this->Mailer != 'mail') { 1458 $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject))); 1459 } 1460 1461 if($this->MessageID != '') { 1462 $result .= $this->HeaderLine('Message-ID', $this->MessageID); 1463 } else { 1464 $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); 1465 } 1466 $result .= $this->HeaderLine('X-Priority', $this->Priority); 1467 if ($this->XMailer == '') { 1468 $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (https://github.com/PHPMailer/PHPMailer/)'); 1469 } else { 1470 $myXmailer = trim($this->XMailer); 1471 if ($myXmailer) { 1472 $result .= $this->HeaderLine('X-Mailer', $myXmailer); 1473 } 1474 } 1475 1476 if($this->ConfirmReadingTo != '') { 1477 $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>'); 1478 } 1479 1480 // Add custom headers 1481 for($index = 0; $index < count($this->CustomHeader); $index++) { 1482 $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1]))); 1483 } 1484 if (!$this->sign_key_file) { 1485 $result .= $this->HeaderLine('MIME-Version', '1.0'); 1486 $result .= $this->GetMailMIME(); 1487 } 1488 1489 return $result; 1490 } 1491 1492 /** 1493 * Returns the message MIME. 1494 * @access public 1495 * @return string 1496 */ 1497 public function GetMailMIME() { 1498 $result = ''; 1499 switch($this->message_type) { 1500 case 'inline': 1501 $result .= $this->HeaderLine('Content-Type', 'multipart/related;'); 1502 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1].'"'); 1503 break; 1504 case 'attach': 1505 case 'inline_attach': 1506 case 'alt_attach': 1507 case 'alt_inline_attach': 1508 $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;'); 1509 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1].'"'); 1510 break; 1511 case 'alt': 1512 case 'alt_inline': 1513 $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;'); 1514 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1].'"'); 1515 break; 1516 default: 1517 // Catches case 'plain': and case '': 1518 $result .= $this->TextLine('Content-Type: '.$this->ContentType.'; charset='.$this->CharSet); 1519 break; 1520 } 1521 //RFC1341 part 5 says 7bit is assumed if not specified 1522 if ($this->Encoding != '7bit') { 1523 $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding); 1524 } 1525 1526 if($this->Mailer != 'mail') { 1527 $result .= $this->LE; 1528 } 1529 1530 return $result; 1531 } 1532 1533 /** 1534 * Returns the MIME message (headers and body). Only really valid post PreSend(). 1535 * @access public 1536 * @return string 1537 */ 1538 public function GetSentMIMEMessage() { 1539 return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody; 1540 } 1541 1542 1543 /** 1544 * Assembles the message body. Returns an empty string on failure. 1545 * @access public 1546 * @throws phpmailerException 1547 * @return string The assembled message body 1548 */ 1549 public function CreateBody() { 1550 $body = ''; 1551 1552 if ($this->sign_key_file) { 1553 $body .= $this->GetMailMIME().$this->LE; 1554 } 1555 1556 $this->SetWordWrap(); 1557 1558 switch($this->message_type) { 1559 case 'inline': 1560 $body .= $this->GetBoundary($this->boundary[1], '', '', ''); 1561 $body .= $this->EncodeString($this->Body, $this->Encoding); 1562 $body .= $this->LE.$this->LE; 1563 $body .= $this->AttachAll('inline', $this->boundary[1]); 1564 break; 1565 case 'attach': 1566 $body .= $this->GetBoundary($this->boundary[1], '', '', ''); 1567 $body .= $this->EncodeString($this->Body, $this->Encoding); 1568 $body .= $this->LE.$this->LE; 1569 $body .= $this->AttachAll('attachment', $this->boundary[1]); 1570 break; 1571 case 'inline_attach': 1572 $body .= $this->TextLine('--' . $this->boundary[1]); 1573 $body .= $this->HeaderLine('Content-Type', 'multipart/related;'); 1574 $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2].'"'); 1575 $body .= $this->LE; 1576 $body .= $this->GetBoundary($this->boundary[2], '', '', ''); 1577 $body .= $this->EncodeString($this->Body, $this->Encoding); 1578 $body .= $this->LE.$this->LE; 1579 $body .= $this->AttachAll('inline', $this->boundary[2]); 1580 $body .= $this->LE; 1581 $body .= $this->AttachAll('attachment', $this->boundary[1]); 1582 break; 1583 case 'alt': 1584 $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', ''); 1585 $body .= $this->EncodeString($this->AltBody, $this->Encoding); 1586 $body .= $this->LE.$this->LE; 1587 $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', ''); 1588 $body .= $this->EncodeString($this->Body, $this->Encoding); 1589 $body .= $this->LE.$this->LE; 1590 if(!empty($this->Ical)) { 1591 $body .= $this->GetBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', ''); 1592 $body .= $this->EncodeString($this->Ical, $this->Encoding); 1593 $body .= $this->LE.$this->LE; 1594 } 1595 $body .= $this->EndBoundary($this->boundary[1]); 1596 break; 1597 case 'alt_inline': 1598 $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', ''); 1599 $body .= $this->EncodeString($this->AltBody, $this->Encoding); 1600 $body .= $this->LE.$this->LE; 1601 $body .= $this->TextLine('--' . $this->boundary[1]); 1602 $body .= $this->HeaderLine('Content-Type', 'multipart/related;'); 1603 $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2].'"'); 1604 $body .= $this->LE; 1605 $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', ''); 1606 $body .= $this->EncodeString($this->Body, $this->Encoding); 1607 $body .= $this->LE.$this->LE; 1608 $body .= $this->AttachAll('inline', $this->boundary[2]); 1609 $body .= $this->LE; 1610 $body .= $this->EndBoundary($this->boundary[1]); 1611 break; 1612 case 'alt_attach': 1613 $body .= $this->TextLine('--' . $this->boundary[1]); 1614 $body .= $this->HeaderLine('Content-Type', 'multipart/alternative;'); 1615 $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2].'"'); 1616 $body .= $this->LE; 1617 $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', ''); 1618 $body .= $this->EncodeString($this->AltBody, $this->Encoding); 1619 $body .= $this->LE.$this->LE; 1620 $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', ''); 1621 $body .= $this->EncodeString($this->Body, $this->Encoding); 1622 $body .= $this->LE.$this->LE; 1623 $body .= $this->EndBoundary($this->boundary[2]); 1624 $body .= $this->LE; 1625 $body .= $this->AttachAll('attachment', $this->boundary[1]); 1626 break; 1627 case 'alt_inline_attach': 1628 $body .= $this->TextLine('--' . $this->boundary[1]); 1629 $body .= $this->HeaderLine('Content-Type', 'multipart/alternative;'); 1630 $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2].'"'); 1631 $body .= $this->LE; 1632 $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', ''); 1633 $body .= $this->EncodeString($this->AltBody, $this->Encoding); 1634 $body .= $this->LE.$this->LE; 1635 $body .= $this->TextLine('--' . $this->boundary[2]); 1636 $body .= $this->HeaderLine('Content-Type', 'multipart/related;'); 1637 $body .= $this->TextLine("\tboundary=\"" . $this->boundary[3].'"'); 1638 $body .= $this->LE; 1639 $body .= $this->GetBoundary($this->boundary[3], '', 'text/html', ''); 1640 $body .= $this->EncodeString($this->Body, $this->Encoding); 1641 $body .= $this->LE.$this->LE; 1642 $body .= $this->AttachAll('inline', $this->boundary[3]); 1643 $body .= $this->LE; 1644 $body .= $this->EndBoundary($this->boundary[2]); 1645 $body .= $this->LE; 1646 $body .= $this->AttachAll('attachment', $this->boundary[1]); 1647 break; 1648 default: 1649 // catch case 'plain' and case '' 1650 $body .= $this->EncodeString($this->Body, $this->Encoding); 1651 break; 1652 } 1653 1654 if ($this->IsError()) { 1655 $body = ''; 1656 } elseif ($this->sign_key_file) { 1657 try { 1658 if (!defined('PKCS7_TEXT')) { 1659 throw new phpmailerException($this->Lang('signing').' OpenSSL extension missing.'); 1660 } 1661 $file = tempnam(sys_get_temp_dir(), 'mail'); 1662 file_put_contents($file, $body); //TODO check this worked 1663 $signed = tempnam(sys_get_temp_dir(), 'signed'); 1664 if (@openssl_pkcs7_sign($file, $signed, 'file://'.realpath($this->sign_cert_file), array('file://'.realpath($this->sign_key_file), $this->sign_key_pass), null)) { 1665 @unlink($file); 1666 $body = file_get_contents($signed); 1667 @unlink($signed); 1668 } else { 1669 @unlink($file); 1670 @unlink($signed); 1671 throw new phpmailerException($this->Lang('signing').openssl_error_string()); 1672 } 1673 } catch (phpmailerException $e) { 1674 $body = ''; 1675 if ($this->exceptions) { 1676 throw $e; 1677 } 1678 } 1679 } 1680 return $body; 1681 } 1682 1683 /** 1684 * Returns the start of a message boundary. 1685 * @access protected 1686 * @param string $boundary 1687 * @param string $charSet 1688 * @param string $contentType 1689 * @param string $encoding 1690 * @return string 1691 */ 1692 protected function GetBoundary($boundary, $charSet, $contentType, $encoding) { 1693 $result = ''; 1694 if($charSet == '') { 1695 $charSet = $this->CharSet; 1696 } 1697 if($contentType == '') { 1698 $contentType = $this->ContentType; 1699 } 1700 if($encoding == '') { 1701 $encoding = $this->Encoding; 1702 } 1703 $result .= $this->TextLine('--' . $boundary); 1704 $result .= sprintf("Content-Type: %s; charset=%s", $contentType, $charSet); 1705 $result .= $this->LE; 1706 $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding); 1707 $result .= $this->LE; 1708 1709 return $result; 1710 } 1711 1712 /** 1713 * Returns the end of a message boundary. 1714 * @access protected 1715 * @param string $boundary 1716 * @return string 1717 */ 1718 protected function EndBoundary($boundary) { 1719 return $this->LE . '--' . $boundary . '--' . $this->LE; 1720 } 1721 1722 /** 1723 * Sets the message type. 1724 * @access protected 1725 * @return void 1726 */ 1727 protected function SetMessageType() { 1728 $this->message_type = array(); 1729 if($this->AlternativeExists()) $this->message_type[] = "alt"; 1730 if($this->InlineImageExists()) $this->message_type[] = "inline"; 1731 if($this->AttachmentExists()) $this->message_type[] = "attach"; 1732 $this->message_type = implode("_", $this->message_type); 1733 if($this->message_type == "") $this->message_type = "plain"; 1734 } 1735 1736 /** 1737 * Returns a formatted header line. 1738 * @access public 1739 * @param string $name 1740 * @param string $value 1741 * @return string 1742 */ 1743 public function HeaderLine($name, $value) { 1744 return $name . ': ' . $value . $this->LE; 1745 } 1746 1747 /** 1748 * Returns a formatted mail line. 1749 * @access public 1750 * @param string $value 1751 * @return string 1752 */ 1753 public function TextLine($value) { 1754 return $value . $this->LE; 1755 } 1756 1757 ///////////////////////////////////////////////// 1758 // CLASS METHODS, ATTACHMENTS 1759 ///////////////////////////////////////////////// 1760 1761 /** 1762 * Adds an attachment from a path on the filesystem. 1763 * Returns false if the file could not be found 1764 * or accessed. 1765 * @param string $path Path to the attachment. 1766 * @param string $name Overrides the attachment name. 1767 * @param string $encoding File encoding (see $Encoding). 1768 * @param string $type File extension (MIME) type. 1769 * @param string $disposition Disposition to use 1770 * @throws phpmailerException 1771 * @return bool 1772 */ 1773 public function AddAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment') { 1774 try { 1775 if ( !@is_file($path) ) { 1776 throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE); 1777 } 1778 1779 //If a MIME type is not specified, try to work it out from the file name 1780 if ($type == '') { 1781 $type = self::filenameToType($path); 1782 } 1783 1784 $filename = basename($path); 1785 if ( $name == '' ) { 1786 $name = $filename; 1787 } 1788 1789 $this->attachment[] = array( 1790 0 => $path, 1791 1 => $filename, 1792 2 => $name, 1793 3 => $encoding, 1794 4 => $type, 1795 5 => false, // isStringAttachment 1796 6 => $disposition, 1797 7 => 0 1798 ); 1799 1800 } catch (phpmailerException $e) { 1801 $this->SetError($e->getMessage()); 1802 if ($this->exceptions) { 1803 throw $e; 1804 } 1805 if ($this->SMTPDebug) { 1806 $this->edebug($e->getMessage()."\n"); 1807 } 1808 return false; 1809 } 1810 return true; 1811 } 1812 1813 /** 1814 * Return the current array of attachments 1815 * @return array 1816 */ 1817 public function GetAttachments() { 1818 return $this->attachment; 1819 } 1820 1821 /** 1822 * Attaches all fs, string, and binary attachments to the message. 1823 * Returns an empty string on failure. 1824 * @access protected 1825 * @param string $disposition_type 1826 * @param string $boundary 1827 * @return string 1828 */ 1829 protected function AttachAll($disposition_type, $boundary) { 1830 // Return text of body 1831 $mime = array(); 1832 $cidUniq = array(); 1833 $incl = array(); 1834 1835 // Add all attachments 1836 foreach ($this->attachment as $attachment) { 1837 // CHECK IF IT IS A VALID DISPOSITION_FILTER 1838 if($attachment[6] == $disposition_type) { 1839 // Check for string attachment 1840 $string = ''; 1841 $path = ''; 1842 $bString = $attachment[5]; 1843 if ($bString) { 1844 $string = $attachment[0]; 1845 } else { 1846 $path = $attachment[0]; 1847 } 1848 1849 $inclhash = md5(serialize($attachment)); 1850 if (in_array($inclhash, $incl)) { continue; } 1851 $incl[] = $inclhash; 1852 $filename = $attachment[1]; 1853 $name = $attachment[2]; 1854 $encoding = $attachment[3]; 1855 $type = $attachment[4]; 1856 $disposition = $attachment[6]; 1857 $cid = $attachment[7]; 1858 if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; } 1859 $cidUniq[$cid] = true; 1860 1861 $mime[] = sprintf("--%s%s", $boundary, $this->LE); 1862 $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE); 1863 $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE); 1864 1865 if($disposition == 'inline') { 1866 $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE); 1867 } 1868 1869 //If a filename contains any of these chars, it should be quoted, but not otherwise: RFC2183 & RFC2045 5.1 1870 //Fixes a warning in IETF's msglint MIME checker 1871 // 1872 // Allow for bypassing the Content-Disposition header totally 1873 if (!(empty($disposition))) { 1874 if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $name)) { 1875 $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE); 1876 } else { 1877 $mime[] = sprintf("Content-Disposition: %s; filename=%s%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE); 1878 } 1879 } else { 1880 $mime[] = $this->LE; 1881 } 1882 1883 // Encode as string attachment 1884 if($bString) { 1885 $mime[] = $this->EncodeString($string, $encoding); 1886 if($this->IsError()) { 1887 return ''; 1888 } 1889 $mime[] = $this->LE.$this->LE; 1890 } else { 1891 $mime[] = $this->EncodeFile($path, $encoding); 1892 if($this->IsError()) { 1893 return ''; 1894 } 1895 $mime[] = $this->LE.$this->LE; 1896 } 1897 } 1898 } 1899 1900 $mime[] = sprintf("--%s--%s", $boundary, $this->LE); 1901 1902 return implode("", $mime); 1903 } 1904 1905 /** 1906 * Encodes attachment in requested format. 1907 * Returns an empty string on failure. 1908 * @param string $path The full path to the file 1909 * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' 1910 * @throws phpmailerException 1911 * @see EncodeFile() 1912 * @access protected 1913 * @return string 1914 */ 1915 protected function EncodeFile($path, $encoding = 'base64') { 1916 try { 1917 if (!is_readable($path)) { 1918 throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE); 1919 } 1920 $magic_quotes = get_magic_quotes_runtime(); 1921 if ($magic_quotes) { 1922 if (version_compare(PHP_VERSION, '5.3.0', '<')) { 1923 set_magic_quotes_runtime(0); 1924 } else { 1925 ini_set('magic_quotes_runtime', 0); 1926 } 1927 } 1928 $file_buffer = file_get_contents($path); 1929 $file_buffer = $this->EncodeString($file_buffer, $encoding); 1930 if ($magic_quotes) { 1931 if (version_compare(PHP_VERSION, '5.3.0', '<')) { 1932 set_magic_quotes_runtime($magic_quotes); 1933 } else { 1934 ini_set('magic_quotes_runtime', $magic_quotes); 1935 } 1936 } 1937 return $file_buffer; 1938 } catch (Exception $e) { 1939 $this->SetError($e->getMessage()); 1940 return ''; 1941 } 1942 } 1943 1944 /** 1945 * Encodes string to requested format. 1946 * Returns an empty string on failure. 1947 * @param string $str The text to encode 1948 * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' 1949 * @access public 1950 * @return string 1951 */ 1952 public function EncodeString($str, $encoding = 'base64') { 1953 $encoded = ''; 1954 switch(strtolower($encoding)) { 1955 case 'base64': 1956 $encoded = chunk_split(base64_encode($str), 76, $this->LE); 1957 break; 1958 case '7bit': 1959 case '8bit': 1960 $encoded = $this->FixEOL($str); 1961 //Make sure it ends with a line break 1962 if (substr($encoded, -(strlen($this->LE))) != $this->LE) 1963 $encoded .= $this->LE; 1964 break; 1965 case 'binary': 1966 $encoded = $str; 1967 break; 1968 case 'quoted-printable': 1969 $encoded = $this->EncodeQP($str); 1970 break; 1971 default: 1972 $this->SetError($this->Lang('encoding') . $encoding); 1973 break; 1974 } 1975 return $encoded; 1976 } 1977 1978 /** 1979 * Encode a header string to best (shortest) of Q, B, quoted or none. 1980 * @access public 1981 * @param string $str 1982 * @param string $position 1983 * @return string 1984 */ 1985 public function EncodeHeader($str, $position = 'text') { 1986 $x = 0; 1987 1988 switch (strtolower($position)) { 1989 case 'phrase': 1990 if (!preg_match('/[\200-\377]/', $str)) { 1991 // Can't use addslashes as we don't know what value has magic_quotes_sybase 1992 $encoded = addcslashes($str, "\0..\37\177\\\""); 1993 if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { 1994 return ($encoded); 1995 } else { 1996 return ("\"$encoded\""); 1997 } 1998 } 1999 $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); 2000 break; 2001 case 'comment': 2002 $x = preg_match_all('/[()"]/', $str, $matches); 2003 // Fall-through 2004 case 'text': 2005 default: 2006 $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); 2007 break; 2008 } 2009 2010 if ($x == 0) { //There are no chars that need encoding 2011 return ($str); 2012 } 2013 2014 $maxlen = 75 - 7 - strlen($this->CharSet); 2015 // Try to select the encoding which should produce the shortest output 2016 if ($x > strlen($str)/3) { //More than a third of the content will need encoding, so B encoding will be most efficient 2017 $encoding = 'B'; 2018 if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) { 2019 // Use a custom function which correctly encodes and wraps long 2020 // multibyte strings without breaking lines within a character 2021 $encoded = $this->Base64EncodeWrapMB($str, "\n"); 2022 } else { 2023 $encoded = base64_encode($str); 2024 $maxlen -= $maxlen % 4; 2025 $encoded = trim(chunk_split($encoded, $maxlen, "\n")); 2026 } 2027 } else { 2028 $encoding = 'Q'; 2029 $encoded = $this->EncodeQ($str, $position); 2030 $encoded = $this->WrapText($encoded, $maxlen, true); 2031 $encoded = str_replace('='.self::CRLF, "\n", trim($encoded)); 2032 } 2033 2034 $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded); 2035 $encoded = trim(str_replace("\n", $this->LE, $encoded)); 2036 2037 return $encoded; 2038 } 2039 2040 /** 2041 * Checks if a string contains multibyte characters. 2042 * @access public 2043 * @param string $str multi-byte text to wrap encode 2044 * @return bool 2045 */ 2046 public function HasMultiBytes($str) { 2047 if (function_exists('mb_strlen')) { 2048 return (strlen($str) > mb_strlen($str, $this->CharSet)); 2049 } else { // Assume no multibytes (we can't handle without mbstring functions anyway) 2050 return false; 2051 } 2052 } 2053 2054 /** 2055 * Correctly encodes and wraps long multibyte strings for mail headers 2056 * without breaking lines within a character. 2057 * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php 2058 * @access public 2059 * @param string $str multi-byte text to wrap encode 2060 * @param string $lf string to use as linefeed/end-of-line 2061 * @return string 2062 */ 2063 public function Base64EncodeWrapMB($str, $lf=null) { 2064 $start = "=?".$this->CharSet."?B?"; 2065 $end = "?="; 2066 $encoded = ""; 2067 if ($lf === null) { 2068 $lf = $this->LE; 2069 } 2070 2071 $mb_length = mb_strlen($str, $this->CharSet); 2072 // Each line must have length <= 75, including $start and $end 2073 $length = 75 - strlen($start) - strlen($end); 2074 // Average multi-byte ratio 2075 $ratio = $mb_length / strlen($str); 2076 // Base64 has a 4:3 ratio 2077 $offset = $avgLength = floor($length * $ratio * .75); 2078 2079 for ($i = 0; $i < $mb_length; $i += $offset) { 2080 $lookBack = 0; 2081 2082 do { 2083 $offset = $avgLength - $lookBack; 2084 $chunk = mb_substr($str, $i, $offset, $this->CharSet); 2085 $chunk = base64_encode($chunk); 2086 $lookBack++; 2087 } 2088 while (strlen($chunk) > $length); 2089 2090 $encoded .= $chunk . $lf; 2091 } 2092 2093 // Chomp the last linefeed 2094 $encoded = substr($encoded, 0, -strlen($lf)); 2095 return $encoded; 2096 } 2097 2098 /** 2099 * Encode string to RFC2045 (6.7) quoted-printable format 2100 * @access public 2101 * @param string $string The text to encode 2102 * @param integer $line_max Number of chars allowed on a line before wrapping 2103 * @return string 2104 * @link PHP version adapted from http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 2105 */ 2106 public function EncodeQP($string, $line_max = 76) { 2107 if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3) 2108 return quoted_printable_encode($string); 2109 } 2110 //Fall back to a pure PHP implementation 2111 $string = str_replace(array('%20', '%0D%0A.', '%0D%0A', '%'), array(' ', "\r\n=2E", "\r\n", '='), rawurlencode($string)); 2112 $string = preg_replace('/[^\r\n]{'.($line_max - 3).'}[^=\r\n]{2}/', "$0=\r\n", $string); 2113 return $string; 2114 } 2115 2116 /** 2117 * Wrapper to preserve BC for old QP encoding function that was removed 2118 * @see EncodeQP() 2119 * @access public 2120 * @param string $string 2121 * @param integer $line_max 2122 * @param bool $space_conv 2123 * @return string 2124 */ 2125 public function EncodeQPphp($string, $line_max = 76, $space_conv = false) { 2126 return $this->EncodeQP($string, $line_max); 2127 } 2128 2129 /** 2130 * Encode string to q encoding. 2131 * @link http://tools.ietf.org/html/rfc2047 2132 * @param string $str the text to encode 2133 * @param string $position Where the text is going to be used, see the RFC for what that means 2134 * @access public 2135 * @return string 2136 */ 2137 public function EncodeQ($str, $position = 'text') { 2138 //There should not be any EOL in the string 2139 $pattern = ''; 2140 $encoded = str_replace(array("\r", "\n"), '', $str); 2141 switch (strtolower($position)) { 2142 case 'phrase': 2143 $pattern = '^A-Za-z0-9!*+\/ -'; 2144 break; 2145 2146 case 'comment': 2147 $pattern = '\(\)"'; 2148 //note that we don't break here! 2149 //for this reason we build the $pattern without including delimiters and [] 2150 2151 case 'text': 2152 default: 2153 //Replace every high ascii, control =, ? and _ characters 2154 //We put \075 (=) as first value to make sure it's the first one in being converted, preventing double encode 2155 $pattern = '\075\000-\011\013\014\016-\037\077\137\177-\377' . $pattern; 2156 break; 2157 } 2158 2159 if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) { 2160 foreach (array_unique($matches[0]) as $char) { 2161 $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded); 2162 } 2163 } 2164 2165 //Replace every spaces to _ (more readable than =20) 2166 return str_replace(' ', '_', $encoded); 2167 } 2168 2169 2170 /** 2171 * Adds a string or binary attachment (non-filesystem) to the list. 2172 * This method can be used to attach ascii or binary data, 2173 * such as a BLOB record from a database. 2174 * @param string $string String attachment data. 2175 * @param string $filename Name of the attachment. 2176 * @param string $encoding File encoding (see $Encoding). 2177 * @param string $type File extension (MIME) type. 2178 * @param string $disposition Disposition to use 2179 * @return void 2180 */ 2181 public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = '', $disposition = 'attachment') { 2182 //If a MIME type is not specified, try to work it out from the file name 2183 if ($type == '') { 2184 $type = self::filenameToType($filename); 2185 } 2186 // Append to $attachment array 2187 $this->attachment[] = array( 2188 0 => $string, 2189 1 => $filename, 2190 2 => basename($filename), 2191 3 => $encoding, 2192 4 => $type, 2193 5 => true, // isStringAttachment 2194 6 => $disposition, 2195 7 => 0 2196 ); 2197 } 2198 2199 /** 2200 * Add an embedded attachment from a file. 2201 * This can include images, sounds, and just about any other document type. 2202 * @param string $path Path to the attachment. 2203 * @param string $cid Content ID of the attachment; Use this to reference 2204 * the content when using an embedded image in HTML. 2205 * @param string $name Overrides the attachment name. 2206 * @param string $encoding File encoding (see $Encoding). 2207 * @param string $type File MIME type. 2208 * @param string $disposition Disposition to use 2209 * @return bool True on successfully adding an attachment 2210 */ 2211 public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline') { 2212 if ( !@is_file($path) ) { 2213 $this->SetError($this->Lang('file_access') . $path); 2214 return false; 2215 } 2216 2217 //If a MIME type is not specified, try to work it out from the file name 2218 if ($type == '') { 2219 $type = self::filenameToType($path); 2220 } 2221 2222 $filename = basename($path); 2223 if ( $name == '' ) { 2224 $name = $filename; 2225 } 2226 2227 // Append to $attachment array 2228 $this->attachment[] = array( 2229 0 => $path, 2230 1 => $filename, 2231 2 => $name, 2232 3 => $encoding, 2233 4 => $type, 2234 5 => false, // isStringAttachment 2235 6 => $disposition, 2236 7 => $cid 2237 ); 2238 return true; 2239 } 2240 2241 2242 /** 2243 * Add an embedded stringified attachment. 2244 * This can include images, sounds, and just about any other document type. 2245 * Be sure to set the $type to an image type for images: 2246 * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'. 2247 * @param string $string The attachment binary data. 2248 * @param string $cid Content ID of the attachment; Use this to reference 2249 * the content when using an embedded image in HTML. 2250 * @param string $name 2251 * @param string $encoding File encoding (see $Encoding). 2252 * @param string $type MIME type. 2253 * @param string $disposition Disposition to use 2254 * @return bool True on successfully adding an attachment 2255 */ 2256 public function AddStringEmbeddedImage($string, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline') { 2257 //If a MIME type is not specified, try to work it out from the name 2258 if ($type == '') { 2259 $type = self::filenameToType($name); 2260 } 2261 2262 // Append to $attachment array 2263 $this->attachment[] = array( 2264 0 => $string, 2265 1 => $name, 2266 2 => $name, 2267 3 => $encoding, 2268 4 => $type, 2269 5 => true, // isStringAttachment 2270 6 => $disposition, 2271 7 => $cid 2272 ); 2273 return true; 2274 } 2275 2276 /** 2277 * Returns true if an inline attachment is present. 2278 * @access public 2279 * @return bool 2280 */ 2281 public function InlineImageExists() { 2282 foreach($this->attachment as $attachment) { 2283 if ($attachment[6] == 'inline') { 2284 return true; 2285 } 2286 } 2287 return false; 2288 } 2289 2290 /** 2291 * Returns true if an attachment (non-inline) is present. 2292 * @return bool 2293 */ 2294 public function AttachmentExists() { 2295 foreach($this->attachment as $attachment) { 2296 if ($attachment[6] == 'attachment') { 2297 return true; 2298 } 2299 } 2300 return false; 2301 } 2302 2303 /** 2304 * Does this message have an alternative body set? 2305 * @return bool 2306 */ 2307 public function AlternativeExists() { 2308 return !empty($this->AltBody); 2309 } 2310 2311 ///////////////////////////////////////////////// 2312 // CLASS METHODS, MESSAGE RESET 2313 ///////////////////////////////////////////////// 2314 2315 /** 2316 * Clears all recipients assigned in the TO array. Returns void. 2317 * @return void 2318 */ 2319 public function ClearAddresses() { 2320 foreach($this->to as $to) { 2321 unset($this->all_recipients[strtolower($to[0])]); 2322 } 2323 $this->to = array(); 2324 } 2325 2326 /** 2327 * Clears all recipients assigned in the CC array. Returns void. 2328 * @return void 2329 */ 2330 public function ClearCCs() { 2331 foreach($this->cc as $cc) { 2332 unset($this->all_recipients[strtolower($cc[0])]); 2333 } 2334 $this->cc = array(); 2335 } 2336 2337 /** 2338 * Clears all recipients assigned in the BCC array. Returns void. 2339 * @return void 2340 */ 2341 public function ClearBCCs() { 2342 foreach($this->bcc as $bcc) { 2343 unset($this->all_recipients[strtolower($bcc[0])]); 2344 } 2345 $this->bcc = array(); 2346 } 2347 2348 /** 2349 * Clears all recipients assigned in the ReplyTo array. Returns void. 2350 * @return void 2351 */ 2352 public function ClearReplyTos() { 2353 $this->ReplyTo = array(); 2354 } 2355 2356 /** 2357 * Clears all recipients assigned in the TO, CC and BCC 2358 * array. Returns void. 2359 * @return void 2360 */ 2361 public function ClearAllRecipients() { 2362 $this->to = array(); 2363 $this->cc = array(); 2364 $this->bcc = array(); 2365 $this->all_recipients = array(); 2366 } 2367 2368 /** 2369 * Clears all previously set filesystem, string, and binary 2370 * attachments. Returns void. 2371 * @return void 2372 */ 2373 public function ClearAttachments() { 2374 $this->attachment = array(); 2375 } 2376 2377 /** 2378 * Clears all custom headers. Returns void. 2379 * @return void 2380 */ 2381 public function ClearCustomHeaders() { 2382 $this->CustomHeader = array(); 2383 } 2384 2385 ///////////////////////////////////////////////// 2386 // CLASS METHODS, MISCELLANEOUS 2387 ///////////////////////////////////////////////// 2388 2389 /** 2390 * Adds the error message to the error container. 2391 * @access protected 2392 * @param string $msg 2393 * @return void 2394 */ 2395 protected function SetError($msg) { 2396 $this->error_count++; 2397 if ($this->Mailer == 'smtp' and !is_null($this->smtp)) { 2398 $lasterror = $this->smtp->getError(); 2399 if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) { 2400 $msg .= '<p>' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n"; 2401 } 2402 } 2403 $this->ErrorInfo = $msg; 2404 } 2405 2406 /** 2407 * Returns the proper RFC 822 formatted date. 2408 * @access public 2409 * @return string 2410 * @static 2411 */ 2412 public static function RFCDate() { 2413 //Set the time zone to whatever the default is to avoid 500 errors 2414 //Will default to UTC if it's not set properly in php.ini 2415 date_default_timezone_set(@date_default_timezone_get()); 2416 return date('D, j M Y H:i:s O'); 2417 } 2418 2419 /** 2420 * Returns the server hostname or 'localhost.localdomain' if unknown. 2421 * @access protected 2422 * @return string 2423 */ 2424 protected function ServerHostname() { 2425 if (!empty($this->Hostname)) { 2426 $result = $this->Hostname; 2427 } elseif (isset($_SERVER['SERVER_NAME'])) { 2428 $result = $_SERVER['SERVER_NAME']; 2429 } else { 2430 $result = 'localhost.localdomain'; 2431 } 2432 2433 return $result; 2434 } 2435 2436 /** 2437 * Returns a message in the appropriate language. 2438 * @access protected 2439 * @param string $key 2440 * @return string 2441 */ 2442 protected function Lang($key) { 2443 if(count($this->language) < 1) { 2444 $this->SetLanguage('en'); // set the default language 2445 } 2446 2447 if(isset($this->language[$key])) { 2448 return $this->language[$key]; 2449 } else { 2450 return 'Language string failed to load: ' . $key; 2451 } 2452 } 2453 2454 /** 2455 * Returns true if an error occurred. 2456 * @access public 2457 * @return bool 2458 */ 2459 public function IsError() { 2460 return ($this->error_count > 0); 2461 } 2462 2463 /** 2464 * Changes every end of line from CRLF, CR or LF to $this->LE. 2465 * @access public 2466 * @param string $str String to FixEOL 2467 * @return string 2468 */ 2469 public function FixEOL($str) { 2470 // condense down to \n 2471 $nstr = str_replace(array("\r\n", "\r"), "\n", $str); 2472 // Now convert LE as needed 2473 if ($this->LE !== "\n") { 2474 $nstr = str_replace("\n", $this->LE, $nstr); 2475 } 2476 return $nstr; 2477 } 2478 2479 /** 2480 * Adds a custom header. $name value can be overloaded to contain 2481 * both header name and value (name:value) 2482 * @access public 2483 * @param string $name custom header name 2484 * @param string $value header value 2485 * @return void 2486 */ 2487 public function AddCustomHeader($name, $value=null) { 2488 if ($value === null) { 2489 // Value passed in as name:value 2490 $this->CustomHeader[] = explode(':', $name, 2); 2491 } else { 2492 $this->CustomHeader[] = array($name, $value); 2493 } 2494 } 2495 2496 /** 2497 * Creates a message from an HTML string, making modifications for inline images and backgrounds 2498 * and creates a plain-text version by converting the HTML 2499 * Overwrites any existing values in $this->Body and $this->AltBody 2500 * @access public 2501 * @param string $message HTML message string 2502 * @param string $basedir baseline directory for path 2503 * @param bool $advanced Whether to use the advanced HTML to text converter 2504 * @return string $message 2505 */ 2506 public function MsgHTML($message, $basedir = '', $advanced = false) { 2507 preg_match_all("/(src|background)=[\"'](.*)[\"']/Ui", $message, $images); 2508 if (isset($images[2])) { 2509 foreach ($images[2] as $i => $url) { 2510 // do not change urls for absolute images (thanks to corvuscorax) 2511 if (!preg_match('#^[A-z]+://#', $url)) { 2512 $filename = basename($url); 2513 $directory = dirname($url); 2514 if ($directory == '.') { 2515 $directory = ''; 2516 } 2517 $cid = md5($url).'@phpmailer.0'; //RFC2392 S 2 2518 if (strlen($basedir) > 1 && substr($basedir, -1) != '/') { 2519 $basedir .= '/'; 2520 } 2521 if (strlen($directory) > 1 && substr($directory, -1) != '/') { 2522 $directory .= '/'; 2523 } 2524 if ($this->AddEmbeddedImage($basedir.$directory.$filename, $cid, $filename, 'base64', self::_mime_types(self::mb_pathinfo($filename, PATHINFO_EXTENSION)))) { 2525 $message = preg_replace("/".$images[1][$i]."=[\"']".preg_quote($url, '/')."[\"']/Ui", $images[1][$i]."=\"cid:".$cid."\"", $message); 2526 } 2527 } 2528 } 2529 } 2530 $this->IsHTML(true); 2531 if (empty($this->AltBody)) { 2532 $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n"; 2533 } 2534 //Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better 2535 $this->Body = $this->NormalizeBreaks($message); 2536 $this->AltBody = $this->NormalizeBreaks($this->html2text($message, $advanced)); 2537 return $this->Body; 2538 } 2539 2540 /** 2541 * Convert an HTML string into a plain text version 2542 * @param string $html The HTML text to convert 2543 * @param bool $advanced Should this use the more complex html2text converter or just a simple one? 2544 * @return string 2545 */ 2546 public function html2text($html, $advanced = false) { 2547 if ($advanced) { 2548 require_once 'extras/class.html2text.php'; 2549 $h = new html2text($html); 2550 return $h->get_text(); 2551 } 2552 return html_entity_decode(trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))), ENT_QUOTES, $this->CharSet); 2553 } 2554 2555 /** 2556 * Gets the MIME type of the embedded or inline image 2557 * @param string $ext File extension 2558 * @access public 2559 * @return string MIME type of ext 2560 * @static 2561 */ 2562 public static function _mime_types($ext = '') { 2563 $mimes = array( 2564 'xl' => 'application/excel', 2565 'hqx' => 'application/mac-binhex40', 2566 'cpt' => 'application/mac-compactpro', 2567 'bin' => 'application/macbinary', 2568 'doc' => 'application/msword', 2569 'word' => 'application/msword', 2570 'class' => 'application/octet-stream', 2571 'dll' => 'application/octet-stream', 2572 'dms' => 'application/octet-stream', 2573 'exe' => 'application/octet-stream', 2574 'lha' => 'application/octet-stream', 2575 'lzh' => 'application/octet-stream', 2576 'psd' => 'application/octet-stream', 2577 'sea' => 'application/octet-stream', 2578 'so' => 'application/octet-stream', 2579 'oda' => 'application/oda', 2580 'pdf' => 'application/pdf', 2581 'ai' => 'application/postscript', 2582 'eps' => 'application/postscript', 2583 'ps' => 'application/postscript', 2584 'smi' => 'application/smil', 2585 'smil' => 'application/smil', 2586 'mif' => 'application/vnd.mif', 2587 'xls' => 'application/vnd.ms-excel', 2588 'ppt' => 'application/vnd.ms-powerpoint', 2589 'wbxml' => 'application/vnd.wap.wbxml', 2590 'wmlc' => 'application/vnd.wap.wmlc', 2591 'dcr' => 'application/x-director', 2592 'dir' => 'application/x-director', 2593 'dxr' => 'application/x-director', 2594 'dvi' => 'application/x-dvi', 2595 'gtar' => 'application/x-gtar', 2596 'php3' => 'application/x-httpd-php', 2597 'php4' => 'application/x-httpd-php', 2598 'php' => 'application/x-httpd-php', 2599 'phtml' => 'application/x-httpd-php', 2600 'phps' => 'application/x-httpd-php-source', 2601 'js' => 'application/x-javascript', 2602 'swf' => 'application/x-shockwave-flash', 2603 'sit' => 'application/x-stuffit', 2604 'tar' => 'application/x-tar', 2605 'tgz' => 'application/x-tar', 2606 'xht' => 'application/xhtml+xml', 2607 'xhtml' => 'application/xhtml+xml', 2608 'zip' => 'application/zip', 2609 'mid' => 'audio/midi', 2610 'midi' => 'audio/midi', 2611 'mp2' => 'audio/mpeg', 2612 'mp3' => 'audio/mpeg', 2613 'mpga' => 'audio/mpeg', 2614 'aif' => 'audio/x-aiff', 2615 'aifc' => 'audio/x-aiff', 2616 'aiff' => 'audio/x-aiff', 2617 'ram' => 'audio/x-pn-realaudio', 2618 'rm' => 'audio/x-pn-realaudio', 2619 'rpm' => 'audio/x-pn-realaudio-plugin', 2620 'ra' => 'audio/x-realaudio', 2621 'wav' => 'audio/x-wav', 2622 'bmp' => 'image/bmp', 2623 'gif' => 'image/gif', 2624 'jpeg' => 'image/jpeg', 2625 'jpe' => 'image/jpeg', 2626 'jpg' => 'image/jpeg', 2627 'png' => 'image/png', 2628 'tiff' => 'image/tiff', 2629 'tif' => 'image/tiff', 2630 'eml' => 'message/rfc822', 2631 'css' => 'text/css', 2632 'html' => 'text/html', 2633 'htm' => 'text/html', 2634 'shtml' => 'text/html', 2635 'log' => 'text/plain', 2636 'text' => 'text/plain', 2637 'txt' => 'text/plain', 2638 'rtx' => 'text/richtext', 2639 'rtf' => 'text/rtf', 2640 'xml' => 'text/xml', 2641 'xsl' => 'text/xml', 2642 'mpeg' => 'video/mpeg', 2643 'mpe' => 'video/mpeg', 2644 'mpg' => 'video/mpeg', 2645 'mov' => 'video/quicktime', 2646 'qt' => 'video/quicktime', 2647 'rv' => 'video/vnd.rn-realvideo', 2648 'avi' => 'video/x-msvideo', 2649 'movie' => 'video/x-sgi-movie' 2650 ); 2651 return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)]; 2652 } 2653 2654 /** 2655 * Try to map a file name to a MIME type, default to application/octet-stream 2656 * @param string $filename A file name or full path, does not need to exist as a file 2657 * @return string 2658 * @static 2659 */ 2660 public static function filenameToType($filename) { 2661 //In case the path is a URL, strip any query string before getting extension 2662 $qpos = strpos($filename, '?'); 2663 if ($qpos !== false) { 2664 $filename = substr($filename, 0, $qpos); 2665 } 2666 $pathinfo = self::mb_pathinfo($filename); 2667 return self::_mime_types($pathinfo['extension']); 2668 } 2669 2670 /** 2671 * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe. 2672 * Works similarly to the one in PHP >= 5.2.0 2673 * @link http://www.php.net/manual/en/function.pathinfo.php#107461 2674 * @param string $path A filename or path, does not need to exist as a file 2675 * @param integer|string $options Either a PATHINFO_* constant, or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2 2676 * @return string|array 2677 * @static 2678 */ 2679 public static function mb_pathinfo($path, $options = null) { 2680 $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => ''); 2681 $m = array(); 2682 preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $m); 2683 if(array_key_exists(1, $m)) { 2684 $ret['dirname'] = $m[1]; 2685 } 2686 if(array_key_exists(2, $m)) { 2687 $ret['basename'] = $m[2]; 2688 } 2689 if(array_key_exists(5, $m)) { 2690 $ret['extension'] = $m[5]; 2691 } 2692 if(array_key_exists(3, $m)) { 2693 $ret['filename'] = $m[3]; 2694 } 2695 switch($options) { 2696 case PATHINFO_DIRNAME: 2697 case 'dirname': 2698 return $ret['dirname']; 2699 break; 2700 case PATHINFO_BASENAME: 2701 case 'basename': 2702 return $ret['basename']; 2703 break; 2704 case PATHINFO_EXTENSION: 2705 case 'extension': 2706 return $ret['extension']; 2707 break; 2708 case PATHINFO_FILENAME: 2709 case 'filename': 2710 return $ret['filename']; 2711 break; 2712 default: 2713 return $ret; 2714 } 2715 } 2716 2717 /** 2718 * Set (or reset) Class Objects (variables) 2719 * 2720 * Usage Example: 2721 * $page->set('X-Priority', '3'); 2722 * 2723 * @access public 2724 * @param string $name 2725 * @param mixed $value 2726 * NOTE: will not work with arrays, there are no arrays to set/reset 2727 * @throws phpmailerException 2728 * @return bool 2729 * @todo Should this not be using __set() magic function? 2730 */ 2731 public function set($name, $value = '') { 2732 try { 2733 if (isset($this->$name) ) { 2734 $this->$name = $value; 2735 } else { 2736 throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL); 2737 } 2738 } catch (Exception $e) { 2739 $this->SetError($e->getMessage()); 2740 if ($e->getCode() == self::STOP_CRITICAL) { 2741 return false; 2742 } 2743 } 2744 return true; 2745 } 2746 2747 /** 2748 * Strips newlines to prevent header injection. 2749 * @access public 2750 * @param string $str 2751 * @return string 2752 */ 2753 public function SecureHeader($str) { 2754 return trim(str_replace(array("\r", "\n"), '', $str)); 2755 } 2756 2757 /** 2758 * Normalize UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format 2759 * Defaults to CRLF (for message bodies) and preserves consecutive breaks 2760 * @param string $text 2761 * @param string $breaktype What kind of line break to use, defaults to CRLF 2762 * @return string 2763 * @access public 2764 * @static 2765 */ 2766 public static function NormalizeBreaks($text, $breaktype = "\r\n") { 2767 return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text); 2768 } 2769 2770 2771 /** 2772 * Set the private key file and password to sign the message. 2773 * 2774 * @access public 2775 * @param string $cert_filename 2776 * @param string $key_filename 2777 * @param string $key_pass Password for private key 2778 */ 2779 public function Sign($cert_filename, $key_filename, $key_pass) { 2780 $this->sign_cert_file = $cert_filename; 2781 $this->sign_key_file = $key_filename; 2782 $this->sign_key_pass = $key_pass; 2783 } 2784 2785 /** 2786 * Set the private key file and password to sign the message. 2787 * 2788 * @access public 2789 * @param string $txt 2790 * @return string 2791 */ 2792 public function DKIM_QP($txt) { 2793 $line = ''; 2794 for ($i = 0; $i < strlen($txt); $i++) { 2795 $ord = ord($txt[$i]); 2796 if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) { 2797 $line .= $txt[$i]; 2798 } else { 2799 $line .= "=".sprintf("%02X", $ord); 2800 } 2801 } 2802 return $line; 2803 } 2804 2805 /** 2806 * Generate DKIM signature 2807 * 2808 * @access public 2809 * @param string $s Header 2810 * @throws phpmailerException 2811 * @return string 2812 */ 2813 public function DKIM_Sign($s) { 2814 if (!defined('PKCS7_TEXT')) { 2815 if ($this->exceptions) { 2816 throw new phpmailerException($this->Lang("signing").' OpenSSL extension missing.'); 2817 } 2818 return ''; 2819 } 2820 $privKeyStr = file_get_contents($this->DKIM_private); 2821 if ($this->DKIM_passphrase != '') { 2822 $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); 2823 } else { 2824 $privKey = $privKeyStr; 2825 } 2826 if (openssl_sign($s, $signature, $privKey)) { 2827 return base64_encode($signature); 2828 } 2829 return ''; 2830 } 2831 2832 /** 2833 * Generate DKIM Canonicalization Header 2834 * 2835 * @access public 2836 * @param string $s Header 2837 * @return string 2838 */ 2839 public function DKIM_HeaderC($s) { 2840 $s = preg_replace("/\r\n\s+/", " ", $s); 2841 $lines = explode("\r\n", $s); 2842 foreach ($lines as $key => $line) { 2843 list($heading, $value) = explode(":", $line, 2); 2844 $heading = strtolower($heading); 2845 $value = preg_replace("/\s+/", " ", $value) ; // Compress useless spaces 2846 $lines[$key] = $heading.":".trim($value) ; // Don't forget to remove WSP around the value 2847 } 2848 $s = implode("\r\n", $lines); 2849 return $s; 2850 } 2851 2852 /** 2853 * Generate DKIM Canonicalization Body 2854 * 2855 * @access public 2856 * @param string $body Message Body 2857 * @return string 2858 */ 2859 public function DKIM_BodyC($body) { 2860 if ($body == '') return "\r\n"; 2861 // stabilize line endings 2862 $body = str_replace("\r\n", "\n", $body); 2863 $body = str_replace("\n", "\r\n", $body); 2864 // END stabilize line endings 2865 while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") { 2866 $body = substr($body, 0, strlen($body) - 2); 2867 } 2868 return $body; 2869 } 2870 2871 /** 2872 * Create the DKIM header, body, as new header 2873 * 2874 * @access public 2875 * @param string $headers_line Header lines 2876 * @param string $subject Subject 2877 * @param string $body Body 2878 * @return string 2879 */ 2880 public function DKIM_Add($headers_line, $subject, $body) { 2881 $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms 2882 $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body 2883 $DKIMquery = 'dns/txt'; // Query method 2884 $DKIMtime = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone) 2885 $subject_header = "Subject: $subject"; 2886 $headers = explode($this->LE, $headers_line); 2887 $from_header = ''; 2888 $to_header = ''; 2889 $current = ''; 2890 foreach($headers as $header) { 2891 if (strpos($header, 'From:') === 0) { 2892 $from_header = $header; 2893 $current = 'from_header'; 2894 } elseif (strpos($header, 'To:') === 0) { 2895 $to_header = $header; 2896 $current = 'to_header'; 2897 } else { 2898 if($current && strpos($header, ' =?') === 0){ 2899 $current .= $header; 2900 } else { 2901 $current = ''; 2902 } 2903 } 2904 } 2905 $from = str_replace('|', '=7C', $this->DKIM_QP($from_header)); 2906 $to = str_replace('|', '=7C', $this->DKIM_QP($to_header)); 2907 $subject = str_replace('|', '=7C', $this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable 2908 $body = $this->DKIM_BodyC($body); 2909 $DKIMlen = strlen($body) ; // Length of body 2910 $DKIMb64 = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body 2911 $ident = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";"; 2912 $dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n". 2913 "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n". 2914 "\th=From:To:Subject;\r\n". 2915 "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n". 2916 "\tz=$from\r\n". 2917 "\t|$to\r\n". 2918 "\t|$subject;\r\n". 2919 "\tbh=" . $DKIMb64 . ";\r\n". 2920 "\tb="; 2921 $toSign = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs); 2922 $signed = $this->DKIM_Sign($toSign); 2923 return $dkimhdrs.$signed."\r\n"; 2924 } 2925 2926 /** 2927 * Perform callback 2928 * @param boolean $isSent 2929 * @param string $to 2930 * @param string $cc 2931 * @param string $bcc 2932 * @param string $subject 2933 * @param string $body 2934 * @param string $from 2935 */ 2936 protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from = null) { 2937 if (!empty($this->action_function) && is_callable($this->action_function)) { 2938 $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from); 2939 call_user_func_array($this->action_function, $params); 2940 } 2941 } 2942 } 2943 2944 /** 2945 * Exception handler for PHPMailer 2946 * @package PHPMailer 2947 */ 2948 class phpmailerException extends Exception { 2949 /** 2950 * Prettify error message output 2951 * @return string 2952 */ 2953 public function errorMessage() { 2954 $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n"; 2955 return $errorMsg; 2956 } 2957 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:08:37 2014 | Cross-referenced by PHPXref 0.7.1 |