/openshift/adei

To get this branch, use:
bzr branch http://darksoft.org/webbzr/openshift/adei

« back to all changes in this revision

Viewing changes to includes/PHPMailer-Lite_v5.1/class.phpmailer-lite.php

  • Committer: Suren A. Chilingaryan
  • Date: 2011-01-26 02:48:39 UTC
  • mto: This revision was merged to the branch mainline in revision 212.
  • Revision ID: csa@dside.dyndns.org-20110126024839-nv6qp2ie9stmd2dn
Support of Appled devices by Toni Pirhonen

Show diffs side-by-side

added added

removed removed

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