[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/externals/phpmailer/ -> class.phpmailer.php (source)

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


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1