[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/ -> class-phpmailer.php (source)

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


Generated: Fri May 25 03:56:23 2012 Hosted by follow the white rabbit.