[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-forums/bbpress/bb-includes/backpress/ -> class.mailer.php (source)

   1  <?php
   2  // Last sync [WP11537]
   3  
   4  /*~ class.phpmailer.php
   5  .---------------------------------------------------------------------------.
   6  |  Software: PHPMailer - PHP email class                                    |
   7  |   Version: 2.0.4                                                          |
   8  |   Contact: via sourceforge.net support pages (also www.codeworxtech.com)  |
   9  |      Info: http://phpmailer.sourceforge.net                               |
  10  |   Support: http://sourceforge.net/projects/phpmailer/                     |
  11  | ------------------------------------------------------------------------- |
  12  |    Author: Andy Prevost (project admininistrator)                         |
  13  |    Author: Brent R. Matzelle (original founder)                           |
  14  | Copyright (c) 2004-2007, 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.codeworxtech.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   * PHPMailer - PHP email transport class
  31   * @package PHPMailer
  32   * @author Andy Prevost
  33   * @copyright 2004 - 2009 Andy Prevost
  34   */
  35  
  36  class PHPMailer {
  37  
  38    /////////////////////////////////////////////////
  39    // PROPERTIES, PUBLIC
  40    /////////////////////////////////////////////////
  41  
  42    /**
  43     * Email priority (1 = High, 3 = Normal, 5 = low).
  44     * @var int
  45     */
  46    var $Priority          = 3;
  47  
  48    /**
  49     * Sets the CharSet of the message.
  50     * @var string
  51     */
  52    var $CharSet           = 'iso-8859-1';
  53  
  54    /**
  55     * Sets the Content-type of the message.
  56     * @var string
  57     */
  58    var $ContentType        = 'text/plain';
  59  
  60    /**
  61     * Sets the Encoding of the message. Options for this are "8bit",
  62     * "7bit", "binary", "base64", and "quoted-printable".
  63     * @var string
  64     */
  65    var $Encoding          = '8bit';
  66  
  67    /**
  68     * Holds the most recent mailer error message.
  69     * @var string
  70     */
  71    var $ErrorInfo         = '';
  72  
  73    /**
  74     * Sets the From email address for the message.
  75     * @var string
  76     */
  77    var $From              = 'root@localhost';
  78  
  79    /**
  80     * Sets the From name of the message.
  81     * @var string
  82     */
  83    var $FromName          = 'Root User';
  84  
  85    /**
  86     * Sets the Sender email (Return-Path) of the message.  If not empty,
  87     * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
  88     * @var string
  89     */
  90    var $Sender            = '';
  91  
  92    /**
  93     * Sets the Subject of the message.
  94     * @var string
  95     */
  96    var $Subject           = '';
  97  
  98    /**
  99     * Sets the Body of the message.  This can be either an HTML or text body.
 100     * If HTML then run IsHTML(true).
 101     * @var string
 102     */
 103    var $Body              = '';
 104  
 105    /**
 106     * Sets the text-only body of the message.  This automatically sets the
 107     * email to multipart/alternative.  This body can be read by mail
 108     * clients that do not have HTML email capability such as mutt. Clients
 109     * that can read HTML will view the normal Body.
 110     * @var string
 111     */
 112    var $AltBody           = '';
 113  
 114    /**
 115     * Sets word wrapping on the body of the message to a given number of
 116     * characters.
 117     * @var int
 118     */
 119    var $WordWrap          = 0;
 120  
 121    /**
 122     * Method to send mail: ("mail", "sendmail", or "smtp").
 123     * @var string
 124     */
 125    var $Mailer            = 'mail';
 126  
 127    /**
 128     * Sets the path of the sendmail program.
 129     * @var string
 130     */
 131    var $Sendmail          = '/usr/sbin/sendmail';
 132  
 133    /**
 134     * Path to PHPMailer plugins.  This is now only useful if the SMTP class
 135     * is in a different directory than the PHP include path.
 136     * @var string
 137     */
 138    var $PluginDir         = '';
 139  
 140    /**
 141     * Holds PHPMailer version.
 142     * @var string
 143     */
 144    var $Version           = "2.0.4";
 145  
 146    /**
 147     * Sets the email address that a reading confirmation will be sent.
 148     * @var string
 149     */
 150    var $ConfirmReadingTo  = '';
 151  
 152    /**
 153     * Sets the hostname to use in Message-Id and Received headers
 154     * and as default HELO string. If empty, the value returned
 155     * by SERVER_NAME is used or 'localhost.localdomain'.
 156     * @var string
 157     */
 158    var $Hostname          = '';
 159  
 160    /**
 161     * Sets the message ID to be used in the Message-Id header.
 162     * If empty, a unique id will be generated.
 163     * @var string
 164     */
 165    var $MessageID         = '';
 166  
 167    /////////////////////////////////////////////////
 168    // PROPERTIES FOR SMTP
 169    /////////////////////////////////////////////////
 170  
 171    /**
 172     * Sets the SMTP hosts.  All hosts must be separated by a
 173     * semicolon.  You can also specify a different port
 174     * for each host by using this format: [hostname:port]
 175     * (e.g. "smtp1.example.com:25;smtp2.example.com").
 176     * Hosts will be tried in order.
 177     * @var string
 178     */
 179    var $Host        = 'localhost';
 180  
 181    /**
 182     * Sets the default SMTP server port.
 183     * @var int
 184     */
 185    var $Port        = 25;
 186  
 187    /**
 188     * Sets the SMTP HELO of the message (Default is $Hostname).
 189     * @var string
 190     */
 191    var $Helo        = '';
 192  
 193    /**
 194     * Sets connection prefix.
 195     * Options are "", "ssl" or "tls"
 196     * @var string
 197     */
 198    var $SMTPSecure = "";
 199  
 200    /**
 201     * Sets SMTP authentication. Utilizes the Username and Password variables.
 202     * @var bool
 203     */
 204    var $SMTPAuth     = false;
 205  
 206    /**
 207     * Sets SMTP username.
 208     * @var string
 209     */
 210    var $Username     = '';
 211  
 212    /**
 213     * Sets SMTP password.
 214     * @var string
 215     */
 216    var $Password     = '';
 217  
 218    /**
 219     * Sets the SMTP server timeout in seconds. This function will not
 220     * work with the win32 version.
 221     * @var int
 222     */
 223    var $Timeout      = 10;
 224  
 225    /**
 226     * Sets SMTP class debugging on or off.
 227     * @var bool
 228     */
 229    var $SMTPDebug    = false;
 230  
 231    /**
 232     * Prevents the SMTP connection from being closed after each mail
 233     * sending.  If this is set to true then to close the connection
 234     * requires an explicit call to SmtpClose().
 235     * @var bool
 236     */
 237    var $SMTPKeepAlive = false;
 238  
 239    /**
 240     * Provides the ability to have the TO field process individual
 241     * emails, instead of sending to entire TO addresses
 242     * @var bool
 243     */
 244    var $SingleTo = false;
 245  
 246    /////////////////////////////////////////////////
 247    // PROPERTIES, PRIVATE
 248    /////////////////////////////////////////////////
 249  
 250    var $smtp            = NULL;
 251    var $to              = array();
 252    var $cc              = array();
 253    var $bcc             = array();
 254    var $ReplyTo         = array();
 255    var $attachment      = array();
 256    var $CustomHeader    = array();
 257    var $message_type    = '';
 258    var $boundary        = array();
 259    var $language        = array();
 260    var $error_count     = 0;
 261    var $LE              = "\n";
 262    var $sign_cert_file  = "";
 263    var $sign_key_file   = "";
 264    var $sign_key_pass   = "";
 265  
 266    /////////////////////////////////////////////////
 267    // METHODS, VARIABLES
 268    /////////////////////////////////////////////////
 269  
 270    /**
 271     * Sets message type to HTML.
 272     * @param bool $bool
 273     * @return void
 274     */
 275    function IsHTML($bool) {
 276      if($bool == true) {
 277        $this->ContentType = 'text/html';
 278      } else {
 279        $this->ContentType = 'text/plain';
 280      }
 281    }
 282  
 283    /**
 284     * Sets Mailer to send message using SMTP.
 285     * @return void
 286     */
 287    function IsSMTP() {
 288      $this->Mailer = 'smtp';
 289    }
 290  
 291    /**
 292     * Sets Mailer to send message using PHP mail() function.
 293     * @return void
 294     */
 295    function IsMail() {
 296      $this->Mailer = 'mail';
 297    }
 298  
 299    /**
 300     * Sets Mailer to send message using the $Sendmail program.
 301     * @return void
 302     */
 303    function IsSendmail() {
 304      $this->Mailer = 'sendmail';
 305    }
 306  
 307    /**
 308     * Sets Mailer to send message using the qmail MTA.
 309     * @return void
 310     */
 311    function IsQmail() {
 312      $this->Sendmail = '/var/qmail/bin/sendmail';
 313      $this->Mailer = 'sendmail';
 314    }
 315  
 316    /////////////////////////////////////////////////
 317    // METHODS, RECIPIENTS
 318    /////////////////////////////////////////////////
 319  
 320    /**
 321     * Adds a "To" address.
 322     * @param string $address
 323     * @param string $name
 324     * @return void
 325     */
 326    function AddAddress($address, $name = '') {
 327      $cur = count($this->to);
 328      $this->to[$cur][0] = trim($address);
 329      $this->to[$cur][1] = $name;
 330    }
 331  
 332    /**
 333     * Adds a "Cc" address. Note: this function works
 334     * with the SMTP mailer on win32, not with the "mail"
 335     * mailer.
 336     * @param string $address
 337     * @param string $name
 338     * @return void
 339     */
 340    function AddCC($address, $name = '') {
 341      $cur = count($this->cc);
 342      $this->cc[$cur][0] = trim($address);
 343      $this->cc[$cur][1] = $name;
 344    }
 345  
 346    /**
 347     * Adds a "Bcc" address. Note: this function works
 348     * with the SMTP mailer on win32, not with the "mail"
 349     * mailer.
 350     * @param string $address
 351     * @param string $name
 352     * @return void
 353     */
 354    function AddBCC($address, $name = '') {
 355      $cur = count($this->bcc);
 356      $this->bcc[$cur][0] = trim($address);
 357      $this->bcc[$cur][1] = $name;
 358    }
 359  
 360    /**
 361     * Adds a "Reply-To" address.
 362     * @param string $address
 363     * @param string $name
 364     * @return void
 365     */
 366    function AddReplyTo($address, $name = '') {
 367      $cur = count($this->ReplyTo);
 368      $this->ReplyTo[$cur][0] = trim($address);
 369      $this->ReplyTo[$cur][1] = $name;
 370    }
 371  
 372    /////////////////////////////////////////////////
 373    // METHODS, MAIL SENDING
 374    /////////////////////////////////////////////////
 375  
 376    /**
 377     * Creates message and assigns Mailer. If the message is
 378     * not sent successfully then it returns false.  Use the ErrorInfo
 379     * variable to view description of the error.
 380     * @return bool
 381     */
 382    function Send() {
 383      $header = '';
 384      $body = '';
 385      $result = true;
 386  
 387      if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
 388        $this->SetError($this->Lang('provide_address'));
 389        return false;
 390      }
 391  
 392      /* Set whether the message is multipart/alternative */
 393      if(!empty($this->AltBody)) {
 394        $this->ContentType = 'multipart/alternative';
 395      }
 396  
 397      $this->error_count = 0; // reset errors
 398      $this->SetMessageType();
 399      $header .= $this->CreateHeader();
 400      $body = $this->CreateBody();
 401  
 402      if($body == '') {
 403        return false;
 404      }
 405  
 406      /* Choose the mailer */
 407      switch($this->Mailer) {
 408        case 'sendmail':
 409          $result = $this->SendmailSend($header, $body);
 410          break;
 411        case 'smtp':
 412          $result = $this->SmtpSend($header, $body);
 413          break;
 414        case 'mail':
 415          $result = $this->MailSend($header, $body);
 416          break;
 417        default:
 418          $result = $this->MailSend($header, $body);
 419          break;
 420          //$this->SetError($this->Mailer . $this->Lang('mailer_not_supported'));
 421          //$result = false;
 422          //break;
 423      }
 424  
 425      return $result;
 426    }
 427  
 428    /**
 429     * Sends mail using the $Sendmail program.
 430     * @access private
 431     * @return bool
 432     */
 433    function SendmailSend($header, $body) {
 434      if ($this->Sender != '') {
 435        $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
 436      } else {
 437        $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
 438      }
 439  
 440      if(!@$mail = popen($sendmail, 'w')) {
 441        $this->SetError($this->Lang('execute') . $this->Sendmail);
 442        return false;
 443      }
 444  
 445      fputs($mail, $header);
 446      fputs($mail, $body);
 447  
 448      $result = pclose($mail);
 449      if (version_compare(phpversion(), '4.2.3') == -1) {
 450        $result = $result >> 8 & 0xFF;
 451      }
 452      if($result != 0) {
 453        $this->SetError($this->Lang('execute') . $this->Sendmail);
 454        return false;
 455      }
 456      return true;
 457    }
 458  
 459    /**
 460     * Sends mail using the PHP mail() function.
 461     * @access private
 462     * @return bool
 463     */
 464    function MailSend($header, $body) {
 465  
 466      $to = '';
 467      for($i = 0; $i < count($this->to); $i++) {
 468        if($i != 0) { $to .= ', '; }
 469        $to .= $this->AddrFormat($this->to[$i]);
 470      }
 471  
 472      $toArr = explode(',', $to);
 473  
 474      $params = sprintf("-oi -f %s", $this->Sender);
 475      if ($this->Sender != '' && strlen(ini_get('safe_mode')) < 1) {
 476        $old_from = ini_get('sendmail_from');
 477        ini_set('sendmail_from', $this->Sender);
 478        if ($this->SingleTo === true && count($toArr) > 1) {
 479          foreach ($toArr as $key => $val) {
 480            $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
 481          }
 482        } else {
 483          $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
 484        }
 485      } else {
 486        if ($this->SingleTo === true && count($toArr) > 1) {
 487          foreach ($toArr as $key => $val) {
 488            $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
 489          }
 490        } else {
 491          $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
 492        }
 493      }
 494  
 495      if (isset($old_from)) {
 496        ini_set('sendmail_from', $old_from);
 497      }
 498  
 499      if(!$rt) {
 500        $this->SetError($this->Lang('instantiate'));
 501        return false;
 502      }
 503  
 504      return true;
 505    }
 506  
 507    /**
 508     * Sends mail via SMTP using PhpSMTP (Author:
 509     * Chris Ryan).  Returns bool.  Returns false if there is a
 510     * bad MAIL FROM, RCPT, or DATA input.
 511     * @access private
 512     * @return bool
 513     */
 514    function SmtpSend($header, $body) {
 515      include_once ('class.mailer-smtp.php');
 516      $error = '';
 517      $bad_rcpt = array();
 518  
 519      if(!$this->SmtpConnect()) {
 520        return false;
 521      }
 522  
 523      $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
 524      if(!$this->smtp->Mail($smtp_from)) {
 525        $error = $this->Lang('from_failed') . $smtp_from;
 526        $this->SetError($error);
 527        $this->smtp->Reset();
 528        return false;
 529      }
 530  
 531      /* Attempt to send attach all recipients */
 532      for($i = 0; $i < count($this->to); $i++) {
 533        if(!$this->smtp->Recipient($this->to[$i][0])) {
 534          $bad_rcpt[] = $this->to[$i][0];
 535        }
 536      }
 537      for($i = 0; $i < count($this->cc); $i++) {
 538        if(!$this->smtp->Recipient($this->cc[$i][0])) {
 539          $bad_rcpt[] = $this->cc[$i][0];
 540        }
 541      }
 542      for($i = 0; $i < count($this->bcc); $i++) {
 543        if(!$this->smtp->Recipient($this->bcc[$i][0])) {
 544          $bad_rcpt[] = $this->bcc[$i][0];
 545        }
 546      }
 547  
 548      if(count($bad_rcpt) > 0) { // Create error message
 549        for($i = 0; $i < count($bad_rcpt); $i++) {
 550          if($i != 0) {
 551            $error .= ', ';
 552          }
 553          $error .= $bad_rcpt[$i];
 554        }
 555        $error = $this->Lang('recipients_failed') . $error;
 556        $this->SetError($error);
 557        $this->smtp->Reset();
 558        return false;
 559      }
 560  
 561      if(!$this->smtp->Data($header . $body)) {
 562        $this->SetError($this->Lang('data_not_accepted'));
 563        $this->smtp->Reset();
 564        return false;
 565      }
 566      if($this->SMTPKeepAlive == true) {
 567        $this->smtp->Reset();
 568      } else {
 569        $this->SmtpClose();
 570      }
 571  
 572      return true;
 573    }
 574  
 575    /**
 576     * Initiates a connection to an SMTP server.  Returns false if the
 577     * operation failed.
 578     * @access private
 579     * @return bool
 580     */
 581    function SmtpConnect() {
 582      if($this->smtp == NULL) {
 583        $this->smtp = new SMTP();
 584      }
 585  
 586      $this->smtp->do_debug = $this->SMTPDebug;
 587      $hosts = explode(';', $this->Host);
 588      $index = 0;
 589      $connection = ($this->smtp->Connected());
 590  
 591      /* Retry while there is no connection */
 592      while($index < count($hosts) && $connection == false) {
 593        $hostinfo = array();
 594        if(preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
 595          $host = $hostinfo[1];
 596          $port = $hostinfo[2];
 597        } else {
 598          $host = $hosts[$index];
 599          $port = $this->Port;
 600        }
 601  
 602        if($this->smtp->Connect(((!empty($this->SMTPSecure))?$this->SMTPSecure.'://':'').$host, $port, $this->Timeout)) {
 603          if ($this->Helo != '') {
 604            $this->smtp->Hello($this->Helo);
 605          } else {
 606            $this->smtp->Hello($this->ServerHostname());
 607          }
 608  
 609          $connection = true;
 610          if($this->SMTPAuth) {
 611            if(!$this->smtp->Authenticate($this->Username, $this->Password)) {
 612              $this->SetError($this->Lang('authenticate'));
 613              $this->smtp->Reset();
 614              $connection = false;
 615            }
 616          }
 617        }
 618        $index++;
 619      }
 620      if(!$connection) {
 621        $this->SetError($this->Lang('connect_host'));
 622      }
 623  
 624      return $connection;
 625    }
 626  
 627    /**
 628     * Closes the active SMTP session if one exists.
 629     * @return void
 630     */
 631    function SmtpClose() {
 632      if($this->smtp != NULL) {
 633        if($this->smtp->Connected()) {
 634          $this->smtp->Quit();
 635          $this->smtp->Close();
 636        }
 637      }
 638    }
 639  
 640    /**
 641     * Sets the language for all class error messages.  Returns false
 642     * if it cannot load the language file.  The default language type
 643     * is English.
 644     * @param string $lang_type Type of language (e.g. Portuguese: "br")
 645     * @param string $lang_path Path to the language file directory
 646     * @access public
 647     * @return bool
 648     */
 649    function SetLanguage($lang_type, $lang_path = 'language/') {
 650      if(file_exists($lang_path.'phpmailer.lang-'.$lang_type.'.php')) {
 651        include($lang_path.'phpmailer.lang-'.$lang_type.'.php');
 652      } elseif (file_exists($lang_path.'phpmailer.lang-en.php')) {
 653        include($lang_path.'phpmailer.lang-en.php');
 654      } else {
 655        $PHPMAILER_LANG = array();
 656        $PHPMAILER_LANG["provide_address"]      = 'You must provide at least one ' .
 657        $PHPMAILER_LANG["mailer_not_supported"] = ' mailer is not supported.';
 658        $PHPMAILER_LANG["execute"]              = 'Could not execute: ';
 659        $PHPMAILER_LANG["instantiate"]          = 'Could not instantiate mail function.';
 660        $PHPMAILER_LANG["authenticate"]         = 'SMTP Error: Could not authenticate.';
 661        $PHPMAILER_LANG["from_failed"]          = 'The following From address failed: ';
 662        $PHPMAILER_LANG["recipients_failed"]    = 'SMTP Error: The following ' .
 663        $PHPMAILER_LANG["data_not_accepted"]    = 'SMTP Error: Data not accepted.';
 664        $PHPMAILER_LANG["connect_host"]         = 'SMTP Error: Could not connect to SMTP host.';
 665        $PHPMAILER_LANG["file_access"]          = 'Could not access file: ';
 666        $PHPMAILER_LANG["file_open"]            = 'File Error: Could not open file: ';
 667        $PHPMAILER_LANG["encoding"]             = 'Unknown encoding: ';
 668        $PHPMAILER_LANG["signing"]              = 'Signing Error: ';
 669      }
 670      $this->language = $PHPMAILER_LANG;
 671  
 672      return true;
 673    }
 674  
 675    /////////////////////////////////////////////////
 676    // METHODS, MESSAGE CREATION
 677    /////////////////////////////////////////////////
 678  
 679    /**
 680     * Creates recipient headers.
 681     * @access private
 682     * @return string
 683     */
 684    function AddrAppend($type, $addr) {
 685      $addr_str = $type . ': ';
 686      $addr_str .= $this->AddrFormat($addr[0]);
 687      if(count($addr) > 1) {
 688        for($i = 1; $i < count($addr); $i++) {
 689          $addr_str .= ', ' . $this->AddrFormat($addr[$i]);
 690        }
 691      }
 692      $addr_str .= $this->LE;
 693  
 694      return $addr_str;
 695    }
 696  
 697    /**
 698     * Formats an address correctly.
 699     * @access private
 700     * @return string
 701     */
 702    function AddrFormat($addr) {
 703      if(empty($addr[1])) {
 704        $formatted = $this->SecureHeader($addr[0]);
 705      } else {
 706        $formatted = $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
 707      }
 708  
 709      return $formatted;
 710    }
 711  
 712    /**
 713     * Wraps message for use with mailers that do not
 714     * automatically perform wrapping and for quoted-printable.
 715     * Original written by philippe.
 716     * @access private
 717     * @return string
 718     */
 719    function WrapText($message, $length, $qp_mode = false) {
 720      $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
 721      // If utf-8 encoding is used, we will need to make sure we don't
 722      // split multibyte characters when we wrap
 723      $is_utf8 = (strtolower($this->CharSet) == "utf-8");
 724  
 725      $message = $this->FixEOL($message);
 726      if (substr($message, -1) == $this->LE) {
 727        $message = substr($message, 0, -1);
 728      }
 729  
 730      $line = explode($this->LE, $message);
 731      $message = '';
 732      for ($i=0 ;$i < count($line); $i++) {
 733        $line_part = explode(' ', $line[$i]);
 734        $buf = '';
 735        for ($e = 0; $e<count($line_part); $e++) {
 736          $word = $line_part[$e];
 737          if ($qp_mode and (strlen($word) > $length)) {
 738            $space_left = $length - strlen($buf) - 1;
 739            if ($e != 0) {
 740              if ($space_left > 20) {
 741                $len = $space_left;
 742                if ($is_utf8) {
 743                  $len = $this->UTF8CharBoundary($word, $len);
 744                } elseif (substr($word, $len - 1, 1) == "=") {
 745                  $len--;
 746                } elseif (substr($word, $len - 2, 1) == "=") {
 747                  $len -= 2;
 748                }
 749                $part = substr($word, 0, $len);
 750                $word = substr($word, $len);
 751                $buf .= ' ' . $part;
 752                $message .= $buf . sprintf("=%s", $this->LE);
 753              } else {
 754                $message .= $buf . $soft_break;
 755              }
 756              $buf = '';
 757            }
 758            while (strlen($word) > 0) {
 759              $len = $length;
 760              if ($is_utf8) {
 761                $len = $this->UTF8CharBoundary($word, $len);
 762              } elseif (substr($word, $len - 1, 1) == "=") {
 763                $len--;
 764              } elseif (substr($word, $len - 2, 1) == "=") {
 765                $len -= 2;
 766              }
 767              $part = substr($word, 0, $len);
 768              $word = substr($word, $len);
 769  
 770              if (strlen($word) > 0) {
 771                $message .= $part . sprintf("=%s", $this->LE);
 772              } else {
 773                $buf = $part;
 774              }
 775            }
 776          } else {
 777            $buf_o = $buf;
 778            $buf .= ($e == 0) ? $word : (' ' . $word);
 779  
 780            if (strlen($buf) > $length and $buf_o != '') {
 781              $message .= $buf_o . $soft_break;
 782              $buf = $word;
 783            }
 784          }
 785        }
 786        $message .= $buf . $this->LE;
 787      }
 788  
 789      return $message;
 790    }
 791  
 792    /**
 793     * Finds last character boundary prior to maxLength in a utf-8
 794     * quoted (printable) encoded string.
 795     * Original written by Colin Brown.
 796     * @access private
 797     * @param string $encodedText utf-8 QP text
 798     * @param int    $maxLength   find last character boundary prior to this length
 799     * @return int
 800     */
 801    function UTF8CharBoundary($encodedText, $maxLength) {
 802      $foundSplitPos = false;
 803      $lookBack = 3;
 804      while (!$foundSplitPos) {
 805        $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
 806        $encodedCharPos = strpos($lastChunk, "=");
 807        if ($encodedCharPos !== false) {
 808          // Found start of encoded character byte within $lookBack block.
 809          // Check the encoded byte value (the 2 chars after the '=')
 810          $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
 811          $dec = hexdec($hex);
 812          if ($dec < 128) { // Single byte character.
 813            // If the encoded char was found at pos 0, it will fit
 814            // otherwise reduce maxLength to start of the encoded char
 815            $maxLength = ($encodedCharPos == 0) ? $maxLength :
 816            $maxLength - ($lookBack - $encodedCharPos);
 817            $foundSplitPos = true;
 818          } elseif ($dec >= 192) { // First byte of a multi byte character
 819            // Reduce maxLength to split at start of character
 820            $maxLength = $maxLength - ($lookBack - $encodedCharPos);
 821            $foundSplitPos = true;
 822          } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
 823            $lookBack += 3;
 824          }
 825        } else {
 826          // No encoded character found
 827          $foundSplitPos = true;
 828        }
 829      }
 830      return $maxLength;
 831    }
 832  
 833    /**
 834     * Set the body wrapping.
 835     * @access private
 836     * @return void
 837     */
 838    function SetWordWrap() {
 839      if($this->WordWrap < 1) {
 840        return;
 841      }
 842  
 843      switch($this->message_type) {
 844        case 'alt':
 845          /* fall through */
 846        case 'alt_attachments':
 847          $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
 848          break;
 849        default:
 850          $this->Body = $this->WrapText($this->Body, $this->WordWrap);
 851          break;
 852      }
 853    }
 854  
 855    /**
 856     * Assembles message header.
 857     * @access private
 858     * @return string
 859     */
 860    function CreateHeader() {
 861      $result = '';
 862  
 863      /* Set the boundaries */
 864      $uniq_id = md5(uniqid(time()));
 865      $this->boundary[1] = 'b1_' . $uniq_id;
 866      $this->boundary[2] = 'b2_' . $uniq_id;
 867  
 868      $result .= $this->HeaderLine('Date', $this->RFCDate());
 869      if($this->Sender == '') {
 870        $result .= $this->HeaderLine('Return-Path', trim($this->From));
 871      } else {
 872        $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
 873      }
 874  
 875      /* To be created automatically by mail() */
 876      if($this->Mailer != 'mail') {
 877        if(count($this->to) > 0) {
 878          $result .= $this->AddrAppend('To', $this->to);
 879        } elseif (count($this->cc) == 0) {
 880          $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
 881        }
 882      }
 883  
 884      $from = array();
 885      $from[0][0] = trim($this->From);
 886      $from[0][1] = $this->FromName;
 887      $result .= $this->AddrAppend('From', $from);
 888  
 889      /* sendmail and mail() extract Cc from the header before sending */
 890      if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->cc) > 0)) {
 891        $result .= $this->AddrAppend('Cc', $this->cc);
 892      }
 893  
 894      /* sendmail and mail() extract Bcc from the header before sending */
 895      if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
 896        $result .= $this->AddrAppend('Bcc', $this->bcc);
 897      }
 898  
 899      if(count($this->ReplyTo) > 0) {
 900        $result .= $this->AddrAppend('Reply-To', $this->ReplyTo);
 901      }
 902  
 903      /* mail() sets the subject itself */
 904      if($this->Mailer != 'mail') {
 905        $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
 906      }
 907  
 908      if($this->MessageID != '') {
 909        $result .= $this->HeaderLine('Message-ID',$this->MessageID);
 910      } else {
 911        $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
 912      }
 913      $result .= $this->HeaderLine('X-Priority', $this->Priority);
 914      $result .= $this->HeaderLine('X-Mailer', 'PHPMailer (phpmailer.sourceforge.net) [version ' . $this->Version . ']');
 915  
 916      if($this->ConfirmReadingTo != '') {
 917        $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
 918      }
 919  
 920      // Add custom headers
 921      for($index = 0; $index < count($this->CustomHeader); $index++) {
 922        $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
 923      }
 924      if (!$this->sign_key_file) {
 925        $result .= $this->HeaderLine('MIME-Version', '1.0');
 926        $result .= $this->GetMailMIME();
 927      }
 928  
 929      return $result;
 930    }
 931  
 932    /**
 933     * Returns the message MIME.
 934     * @access private
 935     * @return string
 936     */
 937    function GetMailMIME() {
 938      $result = '';
 939      switch($this->message_type) {
 940        case 'plain':
 941          $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
 942          $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
 943          break;
 944        case 'attachments':
 945          /* fall through */
 946        case 'alt_attachments':
 947          if($this->InlineImageExists()){
 948            $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
 949          } else {
 950            $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
 951            $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
 952          }
 953          break;
 954        case 'alt':
 955          $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
 956          $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
 957          break;
 958      }
 959  
 960      if($this->Mailer != 'mail') {
 961        $result .= $this->LE.$this->LE;
 962      }
 963  
 964      return $result;
 965    }
 966  
 967    /**
 968     * Assembles the message body.  Returns an empty string on failure.
 969     * @access private
 970     * @return string
 971     */
 972    function CreateBody() {
 973      $result = '';
 974      if ($this->sign_key_file) {
 975        $result .= $this->GetMailMIME();
 976      }
 977  
 978      $this->SetWordWrap();
 979  
 980      switch($this->message_type) {
 981        case 'alt':
 982          $result .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
 983          $result .= $this->EncodeString($this->AltBody, $this->Encoding);
 984          $result .= $this->LE.$this->LE;
 985          $result .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
 986          $result .= $this->EncodeString($this->Body, $this->Encoding);
 987          $result .= $this->LE.$this->LE;
 988          $result .= $this->EndBoundary($this->boundary[1]);
 989          break;
 990        case 'plain':
 991          $result .= $this->EncodeString($this->Body, $this->Encoding);
 992          break;
 993        case 'attachments':
 994          $result .= $this->GetBoundary($this->boundary[1], '', '', '');
 995          $result .= $this->EncodeString($this->Body, $this->Encoding);
 996          $result .= $this->LE;
 997          $result .= $this->AttachAll();
 998          break;
 999        case 'alt_attachments':
1000          $result .= sprintf("--%s%s", $this->boundary[1], $this->LE);
1001          $result .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
1002          $result .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
1003          $result .= $this->EncodeString($this->AltBody, $this->Encoding);
1004          $result .= $this->LE.$this->LE;
1005          $result .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
1006          $result .= $this->EncodeString($this->Body, $this->Encoding);
1007          $result .= $this->LE.$this->LE;
1008          $result .= $this->EndBoundary($this->boundary[2]);
1009          $result .= $this->AttachAll();
1010          break;
1011      }
1012  
1013      if($this->IsError()) {
1014        $result = '';
1015      } else if ($this->sign_key_file) {
1016        $file = tempnam("", "mail");
1017        $fp = fopen($file, "w");
1018        fwrite($fp, $result);
1019        fclose($fp);
1020        $signed = tempnam("", "signed");
1021  
1022        if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), null)) {
1023          $fp = fopen($signed, "r");
1024          $result = fread($fp, filesize($this->sign_key_file));
1025          $result = '';
1026          while(!feof($fp)){
1027            $result = $result . fread($fp, 1024);
1028          }
1029          fclose($fp);
1030        } else {
1031          $this->SetError($this->Lang("signing").openssl_error_string());
1032          $result = '';
1033        }
1034  
1035        unlink($file);
1036        unlink($signed);
1037      }
1038  
1039      return $result;
1040    }
1041  
1042    /**
1043     * Returns the start of a message boundary.
1044     * @access private
1045     */
1046    function GetBoundary($boundary, $charSet, $contentType, $encoding) {
1047      $result = '';
1048      if($charSet == '') {
1049        $charSet = $this->CharSet;
1050      }
1051      if($contentType == '') {
1052        $contentType = $this->ContentType;
1053      }
1054      if($encoding == '') {
1055        $encoding = $this->Encoding;
1056      }
1057      $result .= $this->TextLine('--' . $boundary);
1058      $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
1059      $result .= $this->LE;
1060      $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
1061      $result .= $this->LE;
1062  
1063      return $result;
1064    }
1065  
1066    /**
1067     * Returns the end of a message boundary.
1068     * @access private
1069     */
1070    function EndBoundary($boundary) {
1071      return $this->LE . '--' . $boundary . '--' . $this->LE;
1072    }
1073  
1074    /**
1075     * Sets the message type.
1076     * @access private
1077     * @return void
1078     */
1079    function SetMessageType() {
1080      if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
1081        $this->message_type = 'plain';
1082      } else {
1083        if(count($this->attachment) > 0) {
1084          $this->message_type = 'attachments';
1085        }
1086        if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
1087          $this->message_type = 'alt';
1088        }
1089        if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
1090          $this->message_type = 'alt_attachments';
1091        }
1092      }
1093    }
1094  
1095    /* Returns a formatted header line.
1096     * @access private
1097     * @return string
1098     */
1099    function HeaderLine($name, $value) {
1100      return $name . ': ' . $value . $this->LE;
1101    }
1102  
1103    /**
1104     * Returns a formatted mail line.
1105     * @access private
1106     * @return string
1107     */
1108    function TextLine($value) {
1109      return $value . $this->LE;
1110    }
1111  
1112    /////////////////////////////////////////////////
1113    // CLASS METHODS, ATTACHMENTS
1114    /////////////////////////////////////////////////
1115  
1116    /**
1117     * Adds an attachment from a path on the filesystem.
1118     * Returns false if the file could not be found
1119     * or accessed.
1120     * @param string $path Path to the attachment.
1121     * @param string $name Overrides the attachment name.
1122     * @param string $encoding File encoding (see $Encoding).
1123     * @param string $type File extension (MIME) type.
1124     * @return bool
1125     */
1126    function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1127      if(!@is_file($path)) {
1128        $this->SetError($this->Lang('file_access') . $path);
1129        return false;
1130      }
1131  
1132      $filename = basename($path);
1133      if($name == '') {
1134        $name = $filename;
1135      }
1136  
1137      $cur = count($this->attachment);
1138      $this->attachment[$cur][0] = $path;
1139      $this->attachment[$cur][1] = $filename;
1140      $this->attachment[$cur][2] = $name;
1141      $this->attachment[$cur][3] = $encoding;
1142      $this->attachment[$cur][4] = $type;
1143      $this->attachment[$cur][5] = false; // isStringAttachment
1144      $this->attachment[$cur][6] = 'attachment';
1145      $this->attachment[$cur][7] = 0;
1146  
1147      return true;
1148    }
1149  
1150    /**
1151     * Attaches all fs, string, and binary attachments to the message.
1152     * Returns an empty string on failure.
1153     * @access private
1154     * @return string
1155     */
1156    function AttachAll() {
1157      /* Return text of body */
1158      $mime = array();
1159  
1160      /* Add all attachments */
1161      for($i = 0; $i < count($this->attachment); $i++) {
1162        /* Check for string attachment */
1163        $bString = $this->attachment[$i][5];
1164        if ($bString) {
1165          $string = $this->attachment[$i][0];
1166        } else {
1167          $path = $this->attachment[$i][0];
1168        }
1169  
1170        $filename    = $this->attachment[$i][1];
1171        $name        = $this->attachment[$i][2];
1172        $encoding    = $this->attachment[$i][3];
1173        $type        = $this->attachment[$i][4];
1174        $disposition = $this->attachment[$i][6];
1175        $cid         = $this->attachment[$i][7];
1176  
1177        $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
1178        $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
1179        $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
1180  
1181        if($disposition == 'inline') {
1182          $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
1183        }
1184  
1185        $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
1186  
1187        /* Encode as string attachment */
1188        if($bString) {
1189          $mime[] = $this->EncodeString($string, $encoding);
1190          if($this->IsError()) {
1191            return '';
1192          }
1193          $mime[] = $this->LE.$this->LE;
1194        } else {
1195          $mime[] = $this->EncodeFile($path, $encoding);
1196          if($this->IsError()) {
1197            return '';
1198          }
1199          $mime[] = $this->LE.$this->LE;
1200        }
1201      }
1202  
1203      $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
1204  
1205      return join('', $mime);
1206    }
1207  
1208    /**
1209     * Encodes attachment in requested format.  Returns an
1210     * empty string on failure.
1211     * @access private
1212     * @return string
1213     */
1214    function EncodeFile ($path, $encoding = 'base64') {
1215      if(!@$fd = fopen($path, 'rb')) {
1216        $this->SetError($this->Lang('file_open') . $path);
1217        return '';
1218      }
1219      $magic_quotes = get_magic_quotes_runtime();
1220      if ($magic_quotes) {
1221        if (version_compare(PHP_VERSION, '5.3.0', '<')) {
1222          set_magic_quotes_runtime(0);
1223        } else {
1224          ini_set('magic_quotes_runtime', 0);
1225        }
1226      }
1227      $file_buffer = fread($fd, filesize($path));
1228      $file_buffer = $this->EncodeString($file_buffer, $encoding);
1229      fclose($fd);
1230      if ($magic_quotes) {
1231        if (version_compare(PHP_VERSION, '5.3.0', '<')) {
1232          set_magic_quotes_runtime($magic_quotes);
1233        } else {
1234          ini_set('magic_quotes_runtime', $magic_quotes);
1235        }
1236      }
1237  
1238      return $file_buffer;
1239    }
1240  
1241    /**
1242     * Encodes string to requested format. Returns an
1243     * empty string on failure.
1244     * @access private
1245     * @return string
1246     */
1247    function EncodeString ($str, $encoding = 'base64') {
1248      $encoded = '';
1249      switch(strtolower($encoding)) {
1250        case 'base64':
1251          /* chunk_split is found in PHP >= 3.0.6 */
1252          $encoded = chunk_split(base64_encode($str), 76, $this->LE);
1253          break;
1254        case '7bit':
1255        case '8bit':
1256          $encoded = $this->FixEOL($str);
1257          if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1258            $encoded .= $this->LE;
1259          break;
1260        case 'binary':
1261          $encoded = $str;
1262          break;
1263        case 'quoted-printable':
1264          $encoded = $this->EncodeQP($str);
1265          break;
1266        default:
1267          $this->SetError($this->Lang('encoding') . $encoding);
1268          break;
1269      }
1270      return $encoded;
1271    }
1272  
1273    /**
1274     * Encode a header string to best of Q, B, quoted or none.
1275     * @access private
1276     * @return string
1277     */
1278    function EncodeHeader ($str, $position = 'text') {
1279      $x = 0;
1280  
1281      switch (strtolower($position)) {
1282        case 'phrase':
1283          if (!preg_match('/[\200-\377]/', $str)) {
1284            /* Can't use addslashes as we don't know what value has magic_quotes_sybase. */
1285            $encoded = addcslashes($str, "\0..\37\177\\\"");
1286            if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
1287              return ($encoded);
1288            } else {
1289              return ("\"$encoded\"");
1290            }
1291          }
1292          $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
1293          break;
1294        case 'comment':
1295          $x = preg_match_all('/[()"]/', $str, $matches);
1296          /* Fall-through */
1297        case 'text':
1298        default:
1299          $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
1300          break;
1301      }
1302  
1303      if ($x == 0) {
1304        return ($str);
1305      }
1306  
1307      $maxlen = 75 - 7 - strlen($this->CharSet);
1308      /* Try to select the encoding which should produce the shortest output */
1309      if (strlen($str)/3 < $x) {
1310        $encoding = 'B';
1311        if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
1312       // Use a custom function which correctly encodes and wraps long
1313       // multibyte strings without breaking lines within a character
1314          $encoded = $this->Base64EncodeWrapMB($str);
1315        } else {
1316          $encoded = base64_encode($str);
1317          $maxlen -= $maxlen % 4;
1318          $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
1319        }
1320      } else {
1321        $encoding = 'Q';
1322        $encoded = $this->EncodeQ($str, $position);
1323        $encoded = $this->WrapText($encoded, $maxlen, true);
1324        $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
1325      }
1326  
1327      $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
1328      $encoded = trim(str_replace("\n", $this->LE, $encoded));
1329  
1330      return $encoded;
1331    }
1332  
1333    /**
1334     * Checks if a string contains multibyte characters.
1335     * @access private
1336     * @param string $str multi-byte text to wrap encode
1337     * @return bool
1338     */
1339    function HasMultiBytes($str) {
1340      if (function_exists('mb_strlen')) {
1341        return (strlen($str) > mb_strlen($str, $this->CharSet));
1342      } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
1343        return False;
1344      }
1345    }
1346  
1347    /**
1348     * Correctly encodes and wraps long multibyte strings for mail headers
1349     * without breaking lines within a character.
1350     * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
1351     * @access private
1352     * @param string $str multi-byte text to wrap encode
1353     * @return string
1354     */
1355    function Base64EncodeWrapMB($str) {
1356      $start = "=?".$this->CharSet."?B?";
1357      $end = "?=";
1358      $encoded = "";
1359  
1360      $mb_length = mb_strlen($str, $this->CharSet);
1361      // Each line must have length <= 75, including $start and $end
1362      $length = 75 - strlen($start) - strlen($end);
1363      // Average multi-byte ratio
1364      $ratio = $mb_length / strlen($str);
1365      // Base64 has a 4:3 ratio
1366      $offset = $avgLength = floor($length * $ratio * .75);
1367  
1368      for ($i = 0; $i < $mb_length; $i += $offset) {
1369        $lookBack = 0;
1370  
1371        do {
1372          $offset = $avgLength - $lookBack;
1373          $chunk = mb_substr($str, $i, $offset, $this->CharSet);
1374          $chunk = base64_encode($chunk);
1375          $lookBack++;
1376        }
1377        while (strlen($chunk) > $length);
1378  
1379        $encoded .= $chunk . $this->LE;
1380      }
1381  
1382      // Chomp the last linefeed
1383      $encoded = substr($encoded, 0, -strlen($this->LE));
1384      return $encoded;
1385    }
1386  
1387    /**
1388     * Encode string to quoted-printable.
1389     * @access private
1390     * @return string
1391     */
1392    function EncodeQP( $input = '', $line_max = 76, $space_conv = false ) {
1393      $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
1394      $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
1395      $eol = "\r\n";
1396      $escape = '=';
1397      $output = '';
1398      while( list(, $line) = each($lines) ) {
1399        $linlen = strlen($line);
1400        $newline = '';
1401        for($i = 0; $i < $linlen; $i++) {
1402          $c = substr( $line, $i, 1 );
1403          $dec = ord( $c );
1404          if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
1405            $c = '=2E';
1406          }
1407          if ( $dec == 32 ) {
1408            if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
1409              $c = '=20';
1410            } else if ( $space_conv ) {
1411              $c = '=20';
1412            }
1413          } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
1414            $h2 = floor($dec/16);
1415            $h1 = floor($dec%16);
1416            $c = $escape.$hex[$h2].$hex[$h1];
1417          }
1418          if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
1419            $output .= $newline.$escape.$eol; //  soft line break; " =\r\n" is okay
1420            $newline = '';
1421            // check if newline first character will be point or not
1422            if ( $dec == 46 ) {
1423              $c = '=2E';
1424            }
1425          }
1426          $newline .= $c;
1427        } // end of for
1428        $output .= $newline.$eol;
1429      } // end of while
1430      return $output;
1431    }
1432  
1433    /**
1434     * Callback for converting to "=XX".
1435     * @access private
1436     * @return string
1437     */
1438    function EncodeQ_callback ($matches) {
1439      return sprintf('=%02X', ord($matches[1]));
1440    }
1441  
1442    /**
1443     * Encode string to q encoding.
1444     * @access private
1445     * @return string
1446     */
1447    function EncodeQ ($str, $position = 'text') {
1448      /* There should not be any EOL in the string */
1449      $encoded = preg_replace("/[\r\n]/", '', $str);
1450  
1451      switch (strtolower($position)) {
1452        case 'phrase':
1453          $encoded = preg_replace_callback("/([^A-Za-z0-9!*+\/ -])/",
1454                                           array('PHPMailer', 'EncodeQ_callback'), $encoded);
1455          break;
1456        case 'comment':
1457          $encoded = preg_replace_callback("/([\(\)\"])/",
1458                                           array('PHPMailer', 'EncodeQ_callback'), $encoded);
1459          break;
1460        case 'text':
1461        default:
1462          /* Replace every high ascii, control =, ? and _ characters */
1463          $encoded = preg_replace_callback('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/',
1464                                           array('PHPMailer', 'EncodeQ_callback'), $encoded);
1465          break;
1466      }
1467  
1468      /* Replace every spaces to _ (more readable than =20) */
1469      $encoded = str_replace(' ', '_', $encoded);
1470  
1471      return $encoded;
1472    }
1473  
1474    /**
1475     * Adds a string or binary attachment (non-filesystem) to the list.
1476     * This method can be used to attach ascii or binary data,
1477     * such as a BLOB record from a database.
1478     * @param string $string String attachment data.
1479     * @param string $filename Name of the attachment.
1480     * @param string $encoding File encoding (see $Encoding).
1481     * @param string $type File extension (MIME) type.
1482     * @return void
1483     */
1484    function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
1485      /* Append to $attachment array */
1486      $cur = count($this->attachment);
1487      $this->attachment[$cur][0] = $string;
1488      $this->attachment[$cur][1] = $filename;
1489      $this->attachment[$cur][2] = $filename;
1490      $this->attachment[$cur][3] = $encoding;
1491      $this->attachment[$cur][4] = $type;
1492      $this->attachment[$cur][5] = true; // isString
1493      $this->attachment[$cur][6] = 'attachment';
1494      $this->attachment[$cur][7] = 0;
1495    }
1496  
1497    /**
1498     * Adds an embedded attachment.  This can include images, sounds, and
1499     * just about any other document.  Make sure to set the $type to an
1500     * image type.  For JPEG images use "image/jpeg" and for GIF images
1501     * use "image/gif".
1502     * @param string $path Path to the attachment.
1503     * @param string $cid Content ID of the attachment.  Use this to identify
1504     *        the Id for accessing the image in an HTML form.
1505     * @param string $name Overrides the attachment name.
1506     * @param string $encoding File encoding (see $Encoding).
1507     * @param string $type File extension (MIME) type.
1508     * @return bool
1509     */
1510    function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1511  
1512      if(!@is_file($path)) {
1513        $this->SetError($this->Lang('file_access') . $path);
1514        return false;
1515      }
1516  
1517      $filename = basename($path);
1518      if($name == '') {
1519        $name = $filename;
1520      }
1521  
1522      /* Append to $attachment array */
1523      $cur = count($this->attachment);
1524      $this->attachment[$cur][0] = $path;
1525      $this->attachment[$cur][1] = $filename;
1526      $this->attachment[$cur][2] = $name;
1527      $this->attachment[$cur][3] = $encoding;
1528      $this->attachment[$cur][4] = $type;
1529      $this->attachment[$cur][5] = false;
1530      $this->attachment[$cur][6] = 'inline';
1531      $this->attachment[$cur][7] = $cid;
1532  
1533      return true;
1534    }
1535  
1536    /**
1537     * Returns true if an inline attachment is present.
1538     * @access private
1539     * @return bool
1540     */
1541    function InlineImageExists() {
1542      $result = false;
1543      for($i = 0; $i < count($this->attachment); $i++) {
1544        if($this->attachment[$i][6] == 'inline') {
1545          $result = true;
1546          break;
1547        }
1548      }
1549  
1550      return $result;
1551    }
1552  
1553    /////////////////////////////////////////////////
1554    // CLASS METHODS, MESSAGE RESET
1555    /////////////////////////////////////////////////
1556  
1557    /**
1558     * Clears all recipients assigned in the TO array.  Returns void.
1559     * @return void
1560     */
1561    function ClearAddresses() {
1562      $this->to = array();
1563    }
1564  
1565    /**
1566     * Clears all recipients assigned in the CC array.  Returns void.
1567     * @return void
1568     */
1569    function ClearCCs() {
1570      $this->cc = array();
1571    }
1572  
1573    /**
1574     * Clears all recipients assigned in the BCC array.  Returns void.
1575     * @return void
1576     */
1577    function ClearBCCs() {
1578      $this->bcc = array();
1579    }
1580  
1581    /**
1582     * Clears all recipients assigned in the ReplyTo array.  Returns void.
1583     * @return void
1584     */
1585    function ClearReplyTos() {
1586      $this->ReplyTo = array();
1587    }
1588  
1589    /**
1590     * Clears all recipients assigned in the TO, CC and BCC
1591     * array.  Returns void.
1592     * @return void
1593     */
1594    function ClearAllRecipients() {
1595      $this->to = array();
1596      $this->cc = array();
1597      $this->bcc = array();
1598    }
1599  
1600    /**
1601     * Clears all previously set filesystem, string, and binary
1602     * attachments.  Returns void.
1603     * @return void
1604     */
1605    function ClearAttachments() {
1606      $this->attachment = array();
1607    }
1608  
1609    /**
1610     * Clears all custom headers.  Returns void.
1611     * @return void
1612     */
1613    function ClearCustomHeaders() {
1614      $this->CustomHeader = array();
1615    }
1616  
1617    /////////////////////////////////////////////////
1618    // CLASS METHODS, MISCELLANEOUS
1619    /////////////////////////////////////////////////
1620  
1621    /**
1622     * Adds the error message to the error container.
1623     * Returns void.
1624     * @access private
1625     * @return void
1626     */
1627    function SetError($msg) {
1628      $this->error_count++;
1629      $this->ErrorInfo = $msg;
1630    }
1631  
1632    /**
1633     * Returns the proper RFC 822 formatted date.
1634     * @access private
1635     * @return string
1636     */
1637    function RFCDate() {
1638      $tz = date('Z');
1639      $tzs = ($tz < 0) ? '-' : '+';
1640      $tz = abs($tz);
1641      $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
1642      $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
1643  
1644      return $result;
1645    }
1646  
1647    /**
1648     * Returns the appropriate server variable.  Should work with both
1649     * PHP 4.1.0+ as well as older versions.  Returns an empty string
1650     * if nothing is found.
1651     * @access private
1652     * @return mixed
1653     */
1654    function ServerVar($varName) {
1655      global $HTTP_SERVER_VARS;
1656      global $HTTP_ENV_VARS;
1657  
1658      if(!isset($_SERVER)) {
1659        $_SERVER = $HTTP_SERVER_VARS;
1660        if(!isset($_SERVER['REMOTE_ADDR'])) {
1661          $_SERVER = $HTTP_ENV_VARS; // must be Apache
1662        }
1663      }
1664  
1665      if(isset($_SERVER[$varName])) {
1666        return $_SERVER[$varName];
1667      } else {
1668        return '';
1669      }
1670    }
1671  
1672    /**
1673     * Returns the server hostname or 'localhost.localdomain' if unknown.
1674     * @access private
1675     * @return string
1676     */
1677    function ServerHostname() {
1678      if ($this->Hostname != '') {
1679        $result = $this->Hostname;
1680      } elseif ($this->ServerVar('SERVER_NAME') != '') {
1681        $result = $this->ServerVar('SERVER_NAME');
1682      } else {
1683        $result = 'localhost.localdomain';
1684      }
1685  
1686      return $result;
1687    }
1688  
1689    /**
1690     * Returns a message in the appropriate language.
1691     * @access private
1692     * @return string
1693     */
1694    function Lang($key) {
1695      if(count($this->language) < 1) {
1696        $this->SetLanguage('en'); // set the default language
1697      }
1698  
1699      if(isset($this->language[$key])) {
1700        return $this->language[$key];
1701      } else {
1702        return 'Language string failed to load: ' . $key;
1703      }
1704    }
1705  
1706    /**
1707     * Returns true if an error occurred.
1708     * @return bool
1709     */
1710    function IsError() {
1711      return ($this->error_count > 0);
1712    }
1713  
1714    /**
1715     * Changes every end of line from CR or LF to CRLF.
1716     * @access private
1717     * @return string
1718     */
1719    function FixEOL($str) {
1720      $str = str_replace("\r\n", "\n", $str);
1721      $str = str_replace("\r", "\n", $str);
1722      $str = str_replace("\n", $this->LE, $str);
1723      return $str;
1724    }
1725  
1726    /**
1727     * Adds a custom header.
1728     * @return void
1729     */
1730    function AddCustomHeader($custom_header) {
1731      $this->CustomHeader[] = explode(':', $custom_header, 2);
1732    }
1733  
1734    /**
1735     * Evaluates the message and returns modifications for inline images and backgrounds
1736     * @access public
1737     * @return $message
1738     */
1739    function MsgHTML($message,$basedir='') {
1740      preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images);
1741      if(isset($images[2])) {
1742        foreach($images[2] as $i => $url) {
1743          // do not change urls for absolute images (thanks to corvuscorax)
1744          if (!preg_match('/^[A-z][A-z]*:\/\//',$url)) {
1745            $filename = basename($url);
1746            $directory = dirname($url);
1747            ($directory == '.')?$directory='':'';
1748            $cid = 'cid:' . md5($filename);
1749            $fileParts = explode(".", $filename);
1750            $ext = $fileParts[1];
1751            $mimeType = $this->_mime_types($ext);
1752            if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; }
1753            if ( strlen($directory) > 1 && substr($directory,-1) != '/') { $directory .= '/'; }
1754            if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) {
1755              $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message);
1756            }
1757          }
1758        }
1759      }
1760      $this->IsHTML(true);
1761      $this->Body = $message;
1762      $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message)));
1763      if ( !empty($textMsg) && empty($this->AltBody) ) {
1764        $this->AltBody = html_entity_decode($textMsg);
1765      }
1766      if ( empty($this->AltBody) ) {
1767        $this->AltBody = 'To view this email message, open the email in with HTML compatibility!' . "\n\n";
1768      }
1769    }
1770  
1771    /**
1772     * Gets the mime type of the embedded or inline image
1773     * @access private
1774     * @return mime type of ext
1775     */
1776    function _mime_types($ext = '') {
1777      $mimes = array(
1778        'ai'    =>  'application/postscript',
1779        'aif'   =>  'audio/x-aiff',
1780        'aifc'  =>  'audio/x-aiff',
1781        'aiff'  =>  'audio/x-aiff',
1782        'avi'   =>  'video/x-msvideo',
1783        'bin'   =>  'application/macbinary',
1784        'bmp'   =>  'image/bmp',
1785        'class' =>  'application/octet-stream',
1786        'cpt'   =>  'application/mac-compactpro',
1787        'css'   =>  'text/css',
1788        'dcr'   =>  'application/x-director',
1789        'dir'   =>  'application/x-director',
1790        'dll'   =>  'application/octet-stream',
1791        'dms'   =>  'application/octet-stream',
1792        'doc'   =>  'application/msword',
1793        'dvi'   =>  'application/x-dvi',
1794        'dxr'   =>  'application/x-director',
1795        'eml'   =>  'message/rfc822',
1796        'eps'   =>  'application/postscript',
1797        'exe'   =>  'application/octet-stream',
1798        'gif'   =>  'image/gif',
1799        'gtar'  =>  'application/x-gtar',
1800        'htm'   =>  'text/html',
1801        'html'  =>  'text/html',
1802        'jpe'   =>  'image/jpeg',
1803        'jpeg'  =>  'image/jpeg',
1804        'jpg'   =>  'image/jpeg',
1805        'hqx'   =>  'application/mac-binhex40',
1806        'js'    =>  'application/x-javascript',
1807        'lha'   =>  'application/octet-stream',
1808        'log'   =>  'text/plain',
1809        'lzh'   =>  'application/octet-stream',
1810        'mid'   =>  'audio/midi',
1811        'midi'  =>  'audio/midi',
1812        'mif'   =>  'application/vnd.mif',
1813        'mov'   =>  'video/quicktime',
1814        'movie' =>  'video/x-sgi-movie',
1815        'mp2'   =>  'audio/mpeg',
1816        'mp3'   =>  'audio/mpeg',
1817        'mpe'   =>  'video/mpeg',
1818        'mpeg'  =>  'video/mpeg',
1819        'mpg'   =>  'video/mpeg',
1820        'mpga'  =>  'audio/mpeg',
1821        'oda'   =>  'application/oda',
1822        'pdf'   =>  'application/pdf',
1823        'php'   =>  'application/x-httpd-php',
1824        'php3'  =>  'application/x-httpd-php',
1825        'php4'  =>  'application/x-httpd-php',
1826        'phps'  =>  'application/x-httpd-php-source',
1827        'phtml' =>  'application/x-httpd-php',
1828        'png'   =>  'image/png',
1829        'ppt'   =>  'application/vnd.ms-powerpoint',
1830        'ps'    =>  'application/postscript',
1831        'psd'   =>  'application/octet-stream',
1832        'qt'    =>  'video/quicktime',
1833        'ra'    =>  'audio/x-realaudio',
1834        'ram'   =>  'audio/x-pn-realaudio',
1835        'rm'    =>  'audio/x-pn-realaudio',
1836        'rpm'   =>  'audio/x-pn-realaudio-plugin',
1837        'rtf'   =>  'text/rtf',
1838        'rtx'   =>  'text/richtext',
1839        'rv'    =>  'video/vnd.rn-realvideo',
1840        'sea'   =>  'application/octet-stream',
1841        'shtml' =>  'text/html',
1842        'sit'   =>  'application/x-stuffit',
1843        'so'    =>  'application/octet-stream',
1844        'smi'   =>  'application/smil',
1845        'smil'  =>  'application/smil',
1846        'swf'   =>  'application/x-shockwave-flash',
1847        'tar'   =>  'application/x-tar',
1848        'text'  =>  'text/plain',
1849        'txt'   =>  'text/plain',
1850        'tgz'   =>  'application/x-tar',
1851        'tif'   =>  'image/tiff',
1852        'tiff'  =>  'image/tiff',
1853        'wav'   =>  'audio/x-wav',
1854        'wbxml' =>  'application/vnd.wap.wbxml',
1855        'wmlc'  =>  'application/vnd.wap.wmlc',
1856        'word'  =>  'application/msword',
1857        'xht'   =>  'application/xhtml+xml',
1858        'xhtml' =>  'application/xhtml+xml',
1859        'xl'    =>  'application/excel',
1860        'xls'   =>  'application/vnd.ms-excel',
1861        'xml'   =>  'text/xml',
1862        'xsl'   =>  'text/xml',
1863        'zip'   =>  'application/zip'
1864      );
1865      return ( ! isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
1866    }
1867  
1868    /**
1869     * Set (or reset) Class Objects (variables)
1870     *
1871     * Usage Example:
1872     * $page->set('X-Priority', '3');
1873     *
1874     * @access public
1875     * @param string $name Parameter Name
1876     * @param mixed $value Parameter Value
1877     * NOTE: will not work with arrays, there are no arrays to set/reset
1878     */
1879    function set ( $name, $value = '' ) {
1880      if ( isset($this->$name) ) {
1881        $this->$name = $value;
1882      } else {
1883        $this->SetError('Cannot set or reset variable ' . $name);
1884        return false;
1885      }
1886    }
1887  
1888    /**
1889     * Read a file from a supplied filename and return it.
1890     *
1891     * @access public
1892     * @param string $filename Parameter File Name
1893     */
1894    function getFile($filename) {
1895      $return = '';
1896      if ($fp = fopen($filename, 'rb')) {
1897        while (!feof($fp)) {
1898          $return .= fread($fp, 1024);
1899        }
1900        fclose($fp);
1901        return $return;
1902      } else {
1903        return false;
1904      }
1905    }
1906  
1907    /**
1908     * Strips newlines to prevent header injection.
1909     * @access private
1910     * @param string $str String
1911     * @return string
1912     */
1913    function SecureHeader($str) {
1914      $str = trim($str);
1915      $str = str_replace("\r", "", $str);
1916      $str = str_replace("\n", "", $str);
1917      return $str;
1918    }
1919  
1920    /**
1921     * Set the private key file and password to sign the message.
1922     *
1923     * @access public
1924     * @param string $key_filename Parameter File Name
1925     * @param string $key_pass Password for private key
1926     */
1927    function Sign($cert_filename, $key_filename, $key_pass) {
1928      $this->sign_cert_file = $cert_filename;
1929      $this->sign_key_file = $key_filename;
1930      $this->sign_key_pass = $key_pass;
1931    }
1932  
1933  }


Generated: Thu Nov 21 01:00:57 2024 Cross-referenced by PHPXref 0.7.1