Guest User

class.phpmailer.php

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