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