Source for file phpmailer.php

Documentation is available at phpmailer.php

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

Documentation generated on Tue, 19 Nov 2013 15:10:38 +0100 by phpDocumentor 1.4.3