PageRenderTime 214ms CodeModel.GetById 111ms app.highlight 69ms RepoModel.GetById 14ms app.codeStats 1ms

/library/classes/class.phpmailer.php

https://bitbucket.org/DenizYldrm/openemr
PHP | 2320 lines | 1580 code | 164 blank | 576 comment | 229 complexity | 0436bbe41c408ad59d7493ac937e14df MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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) codeworxtech@users.sourceforge.net |
  12|          : Marcus Bointon (coolbru) coolbru@users.sourceforge.net         |
  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$
  38 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  39 */
  40
  41if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
  42
  43class 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       = 10;
 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 'you@yourdomain.com'
 268   * @var string
 269   */
 270  public $DKIM_identity   = '';
 271
 272  /**
 273   * Used with DKIM DNS Resource Record
 274   * optional, in format of email address 'you@yourdomain.com'
 275   * @var string
 276   */
 277  public $DKIM_domain     = '';
 278
 279  /**
 280   * Used with DKIM DNS Resource Record
 281   * optional, in format of email address 'you@yourdomain.com'
 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    if ($this->SingleTo === true) {
 605      foreach ($this->SingleToArray as $key => $val) {
 606        if(!@$mail = popen($sendmail, 'w')) {
 607          throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
 608        }
 609        fputs($mail, "To: " . $val . "\n");
 610        fputs($mail, $header);
 611        fputs($mail, $body);
 612        $result = pclose($mail);
 613        // implement call back function if it exists
 614        $isSent = ($result == 0) ? 1 : 0;
 615        $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
 616        if($result != 0) {
 617          throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
 618        }
 619      }
 620    } else {
 621      if(!@$mail = popen($sendmail, 'w')) {
 622        throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
 623      }
 624      fputs($mail, $header);
 625      fputs($mail, $body);
 626      $result = pclose($mail);
 627      // implement call back function if it exists
 628      $isSent = ($result == 0) ? 1 : 0;
 629      $this->doCallback($isSent,$this->to,$this->cc,$this->bcc,$this->Subject,$body);
 630      if($result != 0) {
 631        throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
 632      }
 633    }
 634    return true;
 635  }
 636
 637  /**
 638   * Sends mail using the PHP mail() function.
 639   * @param string $header The message headers
 640   * @param string $body The message body
 641   * @access protected
 642   * @return bool
 643   */
 644  protected function MailSend($header, $body) {
 645    $toArr = array();
 646    foreach($this->to as $t) {
 647      $toArr[] = $this->AddrFormat($t);
 648    }
 649    $to = implode(', ', $toArr);
 650
 651    $params = sprintf("-oi -f %s", $this->Sender);
 652    if ($this->Sender != '' && strlen(ini_get('safe_mode'))< 1) {
 653      $old_from = ini_get('sendmail_from');
 654      ini_set('sendmail_from', $this->Sender);
 655      if ($this->SingleTo === true && count($toArr) > 1) {
 656        foreach ($toArr as $key => $val) {
 657          $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
 658          // implement call back function if it exists
 659          $isSent = ($rt == 1) ? 1 : 0;
 660          $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
 661        }
 662      } else {
 663        $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
 664        // implement call back function if it exists
 665        $isSent = ($rt == 1) ? 1 : 0;
 666        $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
 667      }
 668    } else {
 669      if ($this->SingleTo === true && count($toArr) > 1) {
 670        foreach ($toArr as $key => $val) {
 671          $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
 672          // implement call back function if it exists
 673          $isSent = ($rt == 1) ? 1 : 0;
 674          $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
 675        }
 676      } else {
 677        $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
 678        // implement call back function if it exists
 679        $isSent = ($rt == 1) ? 1 : 0;
 680        $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
 681      }
 682    }
 683    if (isset($old_from)) {
 684      ini_set('sendmail_from', $old_from);
 685    }
 686    if(!$rt) {
 687      throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
 688    }
 689    return true;
 690  }
 691
 692  /**
 693   * Sends mail via SMTP using PhpSMTP
 694   * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
 695   * @param string $header The message headers
 696   * @param string $body The message body
 697   * @uses SMTP
 698   * @access protected
 699   * @return bool
 700   */
 701  protected function SmtpSend($header, $body) {
 702    require_once $this->PluginDir . 'class.smtp.php';
 703    $bad_rcpt = array();
 704
 705    if(!$this->SmtpConnect()) {
 706      throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL);
 707    }
 708    $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
 709    if(!$this->smtp->Mail($smtp_from)) {
 710      throw new phpmailerException($this->Lang('from_failed') . $smtp_from, self::STOP_CRITICAL);
 711    }
 712
 713    // Attempt to send attach all recipients
 714    foreach($this->to as $to) {
 715      if (!$this->smtp->Recipient($to[0])) {
 716        $bad_rcpt[] = $to[0];
 717        // implement call back function if it exists
 718        $isSent = 0;
 719        $this->doCallback($isSent,$to[0],'','',$this->Subject,$body);
 720      } else {
 721        // implement call back function if it exists
 722        $isSent = 1;
 723        $this->doCallback($isSent,$to[0],'','',$this->Subject,$body);
 724      }
 725    }
 726    foreach($this->cc as $cc) {
 727      if (!$this->smtp->Recipient($cc[0])) {
 728        $bad_rcpt[] = $cc[0];
 729        // implement call back function if it exists
 730        $isSent = 0;
 731        $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body);
 732      } else {
 733        // implement call back function if it exists
 734        $isSent = 1;
 735        $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body);
 736      }
 737    }
 738    foreach($this->bcc as $bcc) {
 739      if (!$this->smtp->Recipient($bcc[0])) {
 740        $bad_rcpt[] = $bcc[0];
 741        // implement call back function if it exists
 742        $isSent = 0;
 743        $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body);
 744      } else {
 745        // implement call back function if it exists
 746        $isSent = 1;
 747        $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body);
 748      }
 749    }
 750
 751
 752    if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses
 753      $badaddresses = implode(', ', $bad_rcpt);
 754      throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses);
 755    }
 756    if(!$this->smtp->Data($header . $body)) {
 757      throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL);
 758    }
 759    if($this->SMTPKeepAlive == true) {
 760      $this->smtp->Reset();
 761    }
 762    return true;
 763  }
 764
 765  /**
 766   * Initiates a connection to an SMTP server.
 767   * Returns false if the operation failed.
 768   * @uses SMTP
 769   * @access public
 770   * @return bool
 771   */
 772  public function SmtpConnect() {
 773    if(is_null($this->smtp)) {
 774      $this->smtp = new SMTP();
 775    }
 776
 777    $this->smtp->do_debug = $this->SMTPDebug;
 778    $hosts = explode(';', $this->Host);
 779    $index = 0;
 780    $connection = $this->smtp->Connected();
 781
 782    // Retry while there is no connection
 783    try {
 784      while($index < count($hosts) && !$connection) {
 785        $hostinfo = array();
 786        if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
 787          $host = $hostinfo[1];
 788          $port = $hostinfo[2];
 789        } else {
 790          $host = $hosts[$index];
 791          $port = $this->Port;
 792        }
 793
 794        $tls = ($this->SMTPSecure == 'tls');
 795        $ssl = ($this->SMTPSecure == 'ssl');
 796
 797        if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
 798
 799          $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname());
 800          $this->smtp->Hello($hello);
 801
 802          if ($tls) {
 803            if (!$this->smtp->StartTLS()) {
 804              throw new phpmailerException($this->Lang('tls'));
 805            }
 806
 807            //We must resend HELO after tls negotiation
 808            $this->smtp->Hello($hello);
 809          }
 810
 811          $connection = true;
 812          if ($this->SMTPAuth) {
 813            if (!$this->smtp->Authenticate($this->Username, $this->Password)) {
 814              throw new phpmailerException($this->Lang('authenticate'));
 815            }
 816          }
 817        }
 818        $index++;
 819        if (!$connection) {
 820          throw new phpmailerException($this->Lang('connect_host'));
 821        }
 822      }
 823    } catch (phpmailerException $e) {
 824      $this->smtp->Reset();
 825      throw $e;
 826    }
 827    return true;
 828  }
 829
 830  /**
 831   * Closes the active SMTP session if one exists.
 832   * @return void
 833   */
 834  public function SmtpClose() {
 835    if(!is_null($this->smtp)) {
 836      if($this->smtp->Connected()) {
 837        $this->smtp->Quit();
 838        $this->smtp->Close();
 839      }
 840    }
 841  }
 842
 843  /**
 844  * Sets the language for all class error messages.
 845  * Returns false if it cannot load the language file.  The default language is English.
 846  * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
 847  * @param string $lang_path Path to the language file directory
 848  * @access public
 849  */
 850  function SetLanguage($langcode = 'en', $lang_path = 'language/') {
 851    //Define full set of translatable strings
 852    $PHPMAILER_LANG = array(
 853      'provide_address' => 'You must provide at least one recipient email address.',
 854      'mailer_not_supported' => ' mailer is not supported.',
 855      'execute' => 'Could not execute: ',
 856      'instantiate' => 'Could not instantiate mail function.',
 857      'authenticate' => 'SMTP Error: Could not authenticate.',
 858      'from_failed' => 'The following From address failed: ',
 859      'recipients_failed' => 'SMTP Error: The following recipients failed: ',
 860      'data_not_accepted' => 'SMTP Error: Data not accepted.',
 861      'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
 862      'file_access' => 'Could not access file: ',
 863      'file_open' => 'File Error: Could not open file: ',
 864      'encoding' => 'Unknown encoding: ',
 865      'signing' => 'Signing Error: ',
 866      'smtp_error' => 'SMTP server error: ',
 867      'empty_message' => 'Message body empty',
 868      'invalid_address' => 'Invalid address',
 869      'variable_set' => 'Cannot set or reset variable: '
 870    );
 871    //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"!
 872    $l = true;
 873    if ($langcode != 'en') { //There is no English translation file
 874      $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
 875    }
 876    $this->language = $PHPMAILER_LANG;
 877    return ($l == true); //Returns false if language not found
 878  }
 879
 880  /**
 881  * Return the current array of language strings
 882  * @return array
 883  */
 884  public function GetTranslations() {
 885    return $this->language;
 886  }
 887
 888  /////////////////////////////////////////////////
 889  // METHODS, MESSAGE CREATION
 890  /////////////////////////////////////////////////
 891
 892  /**
 893   * Creates recipient headers.
 894   * @access public
 895   * @return string
 896   */
 897  public function AddrAppend($type, $addr) {
 898    $addr_str = $type . ': ';
 899    $addresses = array();
 900    foreach ($addr as $a) {
 901      $addresses[] = $this->AddrFormat($a);
 902    }
 903    $addr_str .= implode(', ', $addresses);
 904    $addr_str .= $this->LE;
 905
 906    return $addr_str;
 907  }
 908
 909  /**
 910   * Formats an address correctly.
 911   * @access public
 912   * @return string
 913   */
 914  public function AddrFormat($addr) {
 915    if (empty($addr[1])) {
 916      return $this->SecureHeader($addr[0]);
 917    } else {
 918      return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
 919    }
 920  }
 921
 922  /**
 923   * Wraps message for use with mailers that do not
 924   * automatically perform wrapping and for quoted-printable.
 925   * Original written by philippe.
 926   * @param string $message The message to wrap
 927   * @param integer $length The line length to wrap to
 928   * @param boolean $qp_mode Whether to run in Quoted-Printable mode
 929   * @access public
 930   * @return string
 931   */
 932  public function WrapText($message, $length, $qp_mode = false) {
 933    $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
 934    // If utf-8 encoding is used, we will need to make sure we don't
 935    // split multibyte characters when we wrap
 936    $is_utf8 = (strtolower($this->CharSet) == "utf-8");
 937
 938    $message = $this->FixEOL($message);
 939    if (substr($message, -1) == $this->LE) {
 940      $message = substr($message, 0, -1);
 941    }
 942
 943    $line = explode($this->LE, $message);
 944    $message = '';
 945    for ($i=0 ;$i < count($line); $i++) {
 946      $line_part = explode(' ', $line[$i]);
 947      $buf = '';
 948      for ($e = 0; $e<count($line_part); $e++) {
 949        $word = $line_part[$e];
 950        if ($qp_mode and (strlen($word) > $length)) {
 951          $space_left = $length - strlen($buf) - 1;
 952          if ($e != 0) {
 953            if ($space_left > 20) {
 954              $len = $space_left;
 955              if ($is_utf8) {
 956                $len = $this->UTF8CharBoundary($word, $len);
 957              } elseif (substr($word, $len - 1, 1) == "=") {
 958                $len--;
 959              } elseif (substr($word, $len - 2, 1) == "=") {
 960                $len -= 2;
 961              }
 962              $part = substr($word, 0, $len);
 963              $word = substr($word, $len);
 964              $buf .= ' ' . $part;
 965              $message .= $buf . sprintf("=%s", $this->LE);
 966            } else {
 967              $message .= $buf . $soft_break;
 968            }
 969            $buf = '';
 970          }
 971          while (strlen($word) > 0) {
 972            $len = $length;
 973            if ($is_utf8) {
 974              $len = $this->UTF8CharBoundary($word, $len);
 975            } elseif (substr($word, $len - 1, 1) == "=") {
 976              $len--;
 977            } elseif (substr($word, $len - 2, 1) == "=") {
 978              $len -= 2;
 979            }
 980            $part = substr($word, 0, $len);
 981            $word = substr($word, $len);
 982
 983            if (strlen($word) > 0) {
 984              $message .= $part . sprintf("=%s", $this->LE);
 985            } else {
 986              $buf = $part;
 987            }
 988          }
 989        } else {
 990          $buf_o = $buf;
 991          $buf .= ($e == 0) ? $word : (' ' . $word);
 992
 993          if (strlen($buf) > $length and $buf_o != '') {
 994            $message .= $buf_o . $soft_break;
 995            $buf = $word;
 996          }
 997        }
 998      }
 999      $message .= $buf . $this->LE;
1000    }
1001
1002    return $message;
1003  }
1004
1005  /**
1006   * Finds last character boundary prior to maxLength in a utf-8
1007   * quoted (printable) encoded string.
1008   * Original written by Colin Brown.
1009   * @access public
1010   * @param string $encodedText utf-8 QP text
1011   * @param int    $maxLength   find last character boundary prior to this length
1012   * @return int
1013   */
1014  public function UTF8CharBoundary($encodedText, $maxLength) {
1015    $foundSplitPos = false;
1016    $lookBack = 3;
1017    while (!$foundSplitPos) {
1018      $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1019      $encodedCharPos = strpos($lastChunk, "=");
1020      if ($encodedCharPos !== false) {
1021        // Found start of encoded character byte within $lookBack block.
1022        // Check the encoded byte value (the 2 chars after the '=')
1023        $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1024        $dec = hexdec($hex);
1025        if ($dec < 128) { // Single byte character.
1026          // If the encoded char was found at pos 0, it will fit
1027          // otherwise reduce maxLength to start of the encoded char
1028          $maxLength = ($encodedCharPos == 0) ? $maxLength :
1029          $maxLength - ($lookBack - $encodedCharPos);
1030          $foundSplitPos = true;
1031        } elseif ($dec >= 192) { // First byte of a multi byte character
1032          // Reduce maxLength to split at start of character
1033          $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1034          $foundSplitPos = true;
1035        } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
1036          $lookBack += 3;
1037        }
1038      } else {
1039        // No encoded character found
1040        $foundSplitPos = true;
1041      }
1042    }
1043    return $maxLength;
1044  }
1045
1046
1047  /**
1048   * Set the body wrapping.
1049   * @access public
1050   * @return void
1051   */
1052  public function SetWordWrap() {
1053    if($this->WordWrap < 1) {
1054      return;
1055    }
1056
1057    switch($this->message_type) {
1058      case 'alt':
1059      case 'alt_attachments':
1060        $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
1061        break;
1062      default:
1063        $this->Body = $this->WrapText($this->Body, $this->WordWrap);
1064        break;
1065    }
1066  }
1067
1068  /**
1069   * Assembles message header.
1070   * @access public
1071   * @return string The assembled header
1072   */
1073  public function CreateHeader() {
1074    $result = '';
1075
1076    // Set the boundaries
1077    $uniq_id = md5(uniqid(time()));
1078    $this->boundary[1] = 'b1_' . $uniq_id;
1079    $this->boundary[2] = 'b2_' . $uniq_id;
1080
1081    $result .= $this->HeaderLine('Date', self::RFCDate());
1082    if($this->Sender == '') {
1083      $result .= $this->HeaderLine('Return-Path', trim($this->From));
1084    } else {
1085      $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
1086    }
1087
1088    // To be created automatically by mail()
1089    if($this->Mailer != 'mail') {
1090      if ($this->SingleTo === true) {
1091        foreach($this->to as $t) {
1092          $this->SingleToArray[] = $this->AddrFormat($t);
1093        }
1094      } else {
1095        if(count($this->to) > 0) {
1096          $result .= $this->AddrAppend('To', $this->to);
1097        } elseif (count($this->cc) == 0) {
1098          $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
1099        }
1100      }
1101    }
1102
1103    $from = array();
1104    $from[0][0] = trim($this->From);
1105    $from[0][1] = $this->FromName;
1106    $result .= $this->AddrAppend('From', $from);
1107
1108    // sendmail and mail() extract Cc from the header before sending
1109    if(count($this->cc) > 0) {
1110      $result .= $this->AddrAppend('Cc', $this->cc);
1111    }
1112
1113    // sendmail and mail() extract Bcc from the header before sending
1114    if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
1115      $result .= $this->AddrAppend('Bcc', $this->bcc);
1116    }
1117
1118    if(count($this->ReplyTo) > 0) {
1119      $result .= $this->AddrAppend('Reply-to', $this->ReplyTo);
1120    }
1121
1122    // mail() sets the subject itself
1123    if($this->Mailer != 'mail') {
1124      $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
1125    }
1126
1127    if($this->MessageID != '') {
1128      $result .= $this->HeaderLine('Message-ID',$this->MessageID);
1129    } else {
1130      $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
1131    }
1132    $result .= $this->HeaderLine('X-Priority', $this->Priority);
1133    $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (phpmailer.sourceforge.net)');
1134
1135    if($this->ConfirmReadingTo != '') {
1136      $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
1137    }
1138
1139    // Add custom headers
1140    for($index = 0; $index < count($this->CustomHeader); $index++) {
1141      $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
1142    }
1143    if (!$this->sign_key_file) {
1144      $result .= $this->HeaderLine('MIME-Version', '1.0');
1145      $result .= $this->GetMailMIME();
1146    }
1147
1148    return $result;
1149  }
1150
1151  /**
1152   * Returns the message MIME.
1153   * @access public
1154   * @return string
1155   */
1156  public function GetMailMIME() {
1157    $result = '';
1158    switch($this->message_type) {
1159      case 'plain':
1160        $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
1161        $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
1162        break;
1163      case 'attachments':
1164      case 'alt_attachments':
1165        if($this->InlineImageExists()){
1166          $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
1167        } else {
1168          $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
1169          $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1170        }
1171        break;
1172      case 'alt':
1173        $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
1174        $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1175        break;
1176    }
1177
1178    if($this->Mailer != 'mail') {
1179      $result .= $this->LE.$this->LE;
1180    }
1181
1182    return $result;
1183  }
1184
1185  /**
1186   * Assembles the message body.  Returns an empty string on failure.
1187   * @access public
1188   * @return string The assembled message body
1189   */
1190  public function CreateBody() {
1191    $body = '';
1192
1193    if ($this->sign_key_file) {
1194      $body .= $this->GetMailMIME();
1195    }
1196
1197    $this->SetWordWrap();
1198
1199    switch($this->message_type) {
1200      case 'alt':
1201        $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
1202        $body .= $this->EncodeString($this->AltBody, $this->Encoding);
1203        $body .= $this->LE.$this->LE;
1204        $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
1205        $body .= $this->EncodeString($this->Body, $this->Encoding);
1206        $body .= $this->LE.$this->LE;
1207        $body .= $this->EndBoundary($this->boundary[1]);
1208        break;
1209      case 'plain':
1210        $body .= $this->EncodeString($this->Body, $this->Encoding);
1211        break;
1212      case 'attachments':
1213        $body .= $this->GetBoundary($this->boundary[1], '', '', '');
1214        $body .= $this->EncodeString($this->Body, $this->Encoding);
1215        $body .= $this->LE;
1216        $body .= $this->AttachAll();
1217        break;
1218      case 'alt_attachments':
1219        $body .= sprintf("--%s%s", $this->boundary[1], $this->LE);
1220        $body .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
1221        $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
1222        $body .= $this->EncodeString($this->AltBody, $this->Encoding);
1223        $body .= $this->LE.$this->LE;
1224        $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
1225        $body .= $this->EncodeString($this->Body, $this->Encoding);
1226        $body .= $this->LE.$this->LE;
1227        $body .= $this->EndBoundary($this->boundary[2]);
1228        $body .= $this->AttachAll();
1229        break;
1230    }
1231
1232    if ($this->IsError()) {
1233      $body = '';
1234    } elseif ($this->sign_key_file) {
1235      try {
1236        $file = tempnam('', 'mail');
1237        file_put_contents($file, $body); //TODO check this worked
1238        $signed = tempnam("", "signed");
1239        if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) {
1240          @unlink($file);
1241          @unlink($signed);
1242          $body = file_get_contents($signed);
1243        } else {
1244          @unlink($file);
1245          @unlink($signed);
1246          throw new phpmailerException($this->Lang("signing").openssl_error_string());
1247        }
1248      } catch (phpmailerException $e) {
1249        $body = '';
1250        if ($this->exceptions) {
1251          throw $e;
1252        }
1253      }
1254    }
1255
1256    return $body;
1257  }
1258
1259  /**
1260   * Returns the start of a message boundary.
1261   * @access private
1262   */
1263  private function GetBoundary($boundary, $charSet, $contentType, $encoding) {
1264    $result = '';
1265    if($charSet == '') {
1266      $charSet = $this->CharSet;
1267    }
1268    if($contentType == '') {
1269      $contentType = $this->ContentType;
1270    }
1271    if($encoding == '') {
1272      $encoding = $this->Encoding;
1273    }
1274    $result .= $this->TextLine('--' . $boundary);
1275    $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
1276    $result .= $this->LE;
1277    $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
1278    $result .= $this->LE;
1279
1280    return $result;
1281  }
1282
1283  /**
1284   * Returns the end of a message boundary.
1285   * @access private
1286   */
1287  private function EndBoundary($boundary) {
1288    return $this->LE . '--' . $boundary . '--' . $this->LE;
1289  }
1290
1291  /**
1292   * Sets the message type.
1293   * @access private
1294   * @return void
1295   */
1296  private function SetMessageType() {
1297    if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
1298      $this->message_type = 'plain';
1299    } else {
1300      if(count($this->attachment) > 0) {
1301        $this->message_type = 'attachments';
1302      }
1303      if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
1304        $this->message_type = 'alt';
1305      }
1306      if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
1307        $this->message_type = 'alt_attachments';
1308      }
1309    }
1310  }
1311
1312  /**
1313   *  Returns a formatted header line.
1314   * @access public
1315   * @return string
1316   */
1317  public function HeaderLine($name, $value) {
1318    return $name . ': ' . $value . $this->LE;
1319  }
1320
1321  /**
1322   * Returns a formatted mail line.
1323   * @access public
1324   * @return string
1325   */
1326  public function TextLine($value) {
1327    return $value . $this->LE;
1328  }
1329
1330  /////////////////////////////////////////////////
1331  // CLASS METHODS, ATTACHMENTS
1332  /////////////////////////////////////////////////
1333
1334  /**
1335   * Adds an attachment from a path on the filesystem.
1336   * Returns false if the file could not be found
1337   * or accessed.
1338   * @param string $path Path to the attachment.
1339   * @param string $name Overrides the attachment name.
1340   * @param string $encoding File encoding (see $Encoding).
1341   * @param string $type File extension (MIME) type.
1342   * @return bool
1343   */
1344  public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1345    try {
1346      if ( !@is_file($path) ) {
1347        throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE);
1348      }
1349      $filename = basename($path);
1350      if ( $name == '' ) {
1351        $name = $filename;
1352      }
1353
1354      $this->attachment[] = array(
1355        0 => $path,
1356        1 => $filename,
1357        2 => $name,
1358        3 => $encoding,
1359        4 => $type,
1360        5 => false,  // isStringAttachment
1361        6 => 'attachment',
1362        7 => 0
1363      );
1364
1365    } catch (phpmailerException $e) {
1366      $this->SetError($e->getMessage());
1367      if ($this->exceptions) {
1368        throw $e;
1369      }
1370      echo $e->getMessage()."\n";
1371      if ( $e->getCode() == self::STOP_CRITICAL ) {
1372        return false;
1373      }
1374    }
1375    return true;
1376  }
1377
1378  /**
1379  * Return the current array of attachments
1380  * @return array
1381  */
1382  public function GetAttachments() {
1383    return $this->attachment;
1384  }
1385
1386  /**
1387   * Attaches all fs, string, and binary attachments to the message.
1388   * Returns an empty string on failure.
1389   * @access private
1390   * @return string
1391   */
1392  private function AttachAll() {
1393    // Return text of body
1394    $mime = array();
1395    $cidUniq = array();
1396    $incl = array();
1397
1398    // Add all attachments
1399    foreach ($this->attachment as $attachment) {
1400      // Check for string attachment
1401      $bString = $attachment[5];
1402      if ($bString) {
1403        $string = $attachment[0];
1404      } else {
1405        $path = $attachment[0];
1406      }
1407
1408      if (in_array($attachment[0], $incl)) { continue; }
1409      $filename    = $attachment[1];
1410      $name        = $attachment[2];
1411      $encoding    = $attachment[3];
1412      $type        = $attachment[4];
1413      $disposition = $attachment[6];
1414      $cid         = $attachment[7];
1415      $incl[]      = $attachment[0];
1416      if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; }
1417      $cidUniq[$cid] = true;
1418
1419      $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
1420      $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
1421      $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
1422
1423      if($disposition == 'inline') {
1424        $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
1425      }
1426
1427      $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
1428
1429      // Encode as string attachment
1430      if($bString) {
1431        $mime[] = $this->EncodeString($string, $encoding);
1432        if($this->IsError()) {
1433          return '';
1434        }
1435        $mime[] = $this->LE.$this->LE;
1436      } else {
1437        $mime[] = $this->EncodeFile($path, $encoding);
1438        if($this->IsError()) {
1439          return '';
1440        }
1441        $mime[] = $this->LE.$this->LE;
1442      }
1443    }
1444
1445    $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
1446
1447    return join('', $mime);
1448  }
1449
1450  /**
1451   * Encodes attachment in requested format.
1452   * Returns an empty string on failure.
1453   * @param string $path The full path to the file
1454   * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
1455   * @see EncodeFile()
1456   * @access private
1457   * @return string
1458   */
1459  private function EncodeFile($path, $encoding = 'base64') {
1460    try {
1461      if (!is_readable($path)) {
1462        throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE);
1463      }
1464      if (function_exists('get_magic_quotes')) {
1465        function get_magic_quotes() {
1466          return false;
1467        }
1468      }
1469      if (PHP_VERSION < 6) {
1470        $magic_quotes = get_magic_quotes_runtime();
1471        set_magic_quotes_runtime(0);
1472      }
1473      $file_buffer  = file_get_contents($path);
1474      $file_buffer  = $this->EncodeString($file_buffer, $encoding);
1475      if (PHP_VERSION < 6) { set_magic_quotes_runtime($magic_quotes); }
1476      return $file_buffer;
1477    } catch (Exception $e) {
1478      $this->SetError($e->getMessage());
1479      return '';
1480    }
1481  }
1482
1483  /**
1484   * Encodes string to requested format.
1485   * Returns an empty string on failure.
1486   * @param string $str The text to encode
1487   * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
1488   * @access public
1489   * @return string
1490   */
1491  public function EncodeString ($str, $encoding = 'base64') {
1492    $encoded = '';
1493    switch(strtolower($encoding)) {
1494      case 'base64':
1495        $encoded = chunk_split(base64_encode($str), 76, $this->LE);
1496        break;
1497      case '7bit':
1498      case '8bit':
1499        $encoded = $this->FixEOL($str);
1500        //Make sure it ends with a line break
1501        if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1502          $encoded .= $this->LE;
1503        break;
1504      case 'binary':
1505        $encoded = $str;
1506        break;
1507      case 'quoted-printable':
1508        $encoded = $this->EncodeQP($str);
1509        break;
1510      default:
1511        $this->SetError($this->Lang('encoding') . $encoding);
1512        break;
1513    }
1514    return $encoded;
1515  }
1516
1517  /**
1518   * Encode a header string to best (shortest) of Q, B, quoted or none.
1519   * @access public
1520   * @return string
1521   */
1522  public function EncodeHeader($str, $position = 'text') {
1523    $x = 0;
1524
1525    switch (strtolower($position)) {
1526      case 'phrase':
1527        if (!preg_match('/[\200-\377]/', $str)) {
1528          // Can't use addslashes as we don't know what value has magic_quotes_sybase
1529          $encoded = addcslashes($str, "\0..\37\177\\\"");
1530          if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
1531            return ($encoded);
1532          } else {
1533            return ("\"$encoded\"");
1534          }
1535        }
1536        $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
1537        break;
1538      case 'comment':
1539        $x = preg_match_all('/[()"]/', $str, $matches);
1540        // Fall-through
1541      case 'text':
1542      default:
1543        $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
1544        break;
1545    }
1546
1547    if ($x == 0) {
1548      return ($str);
1549    }
1550
1551    $maxlen = 75 - 7 - strlen($this->CharSet);
1552    // Try to select the encoding which should produce the shortest output
1553    if (strlen($str)/3 < $x) {
1554      $encoding = 'B';
1555      if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
1556        // Use a custom function which correctly encodes and wraps long
1557        // multibyte strings without breaking lines within a character
1558        $encoded = $this->Base64EncodeWrapMB($str);
1559      } else {
1560        $encoded = base64_encode($str);
1561        $maxlen -= $maxlen % 4;
1562        $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
1563      }
1564    } else {
1565      $encoding = 'Q';
1566      $encoded = $this->EncodeQ($str, $position);
1567      $encoded = $this->WrapText($encoded,

Large files files are truncated, but you can click here to view the full file