Gmail SMTP - Version 1.2.0

Version Description

  • WordPress 5.5 compatibility update.
Download this release

Release Info

Developer naa986
Plugin Icon 128x128 Gmail SMTP
Version 1.2.0
Comparing to
See all releases

Code changes from version 1.1.9 to 1.2.0

Files changed (57) hide show
  1. PHPMailer/PHPMailerAutoload.php +0 -51
  2. PHPMailer/class.phpmailer.php +0 -4044
  3. PHPMailer/class.phpmaileroauth.php +0 -197
  4. PHPMailer/class.phpmaileroauthgoogle.php +0 -77
  5. PHPMailer/class.pop3.php +0 -407
  6. PHPMailer/class.smtp.php +0 -1276
  7. PHPMailer/get_oauth_token.php +0 -162
  8. PHPMailer/language/phpmailer.lang-am.php +0 -26
  9. PHPMailer/language/phpmailer.lang-ar.php +0 -27
  10. PHPMailer/language/phpmailer.lang-az.php +0 -26
  11. PHPMailer/language/phpmailer.lang-ba.php +0 -26
  12. PHPMailer/language/phpmailer.lang-be.php +0 -26
  13. PHPMailer/language/phpmailer.lang-bg.php +0 -26
  14. PHPMailer/language/phpmailer.lang-ca.php +0 -26
  15. PHPMailer/language/phpmailer.lang-ch.php +0 -26
  16. PHPMailer/language/phpmailer.lang-cs.php +0 -25
  17. PHPMailer/language/phpmailer.lang-da.php +0 -26
  18. PHPMailer/language/phpmailer.lang-de.php +0 -25
  19. PHPMailer/language/phpmailer.lang-el.php +0 -25
  20. PHPMailer/language/phpmailer.lang-eo.php +0 -25
  21. PHPMailer/language/phpmailer.lang-es.php +0 -26
  22. PHPMailer/language/phpmailer.lang-et.php +0 -27
  23. PHPMailer/language/phpmailer.lang-fa.php +0 -27
  24. PHPMailer/language/phpmailer.lang-fi.php +0 -27
  25. PHPMailer/language/phpmailer.lang-fo.php +0 -26
  26. PHPMailer/language/phpmailer.lang-fr.php +0 -29
  27. PHPMailer/language/phpmailer.lang-gl.php +0 -26
  28. PHPMailer/language/phpmailer.lang-he.php +0 -26
  29. PHPMailer/language/phpmailer.lang-hr.php +0 -26
  30. PHPMailer/language/phpmailer.lang-hu.php +0 -26
  31. PHPMailer/language/phpmailer.lang-id.php +0 -26
  32. PHPMailer/language/phpmailer.lang-it.php +0 -27
  33. PHPMailer/language/phpmailer.lang-ja.php +0 -27
  34. PHPMailer/language/phpmailer.lang-ka.php +0 -26
  35. PHPMailer/language/phpmailer.lang-ko.php +0 -26
  36. PHPMailer/language/phpmailer.lang-lt.php +0 -26
  37. PHPMailer/language/phpmailer.lang-lv.php +0 -26
  38. PHPMailer/language/phpmailer.lang-ms.php +0 -26
  39. PHPMailer/language/phpmailer.lang-nb.php +0 -25
  40. PHPMailer/language/phpmailer.lang-nl.php +0 -26
  41. PHPMailer/language/phpmailer.lang-pl.php +0 -26
  42. PHPMailer/language/phpmailer.lang-pt.php +0 -26
  43. PHPMailer/language/phpmailer.lang-pt_br.php +0 -29
  44. PHPMailer/language/phpmailer.lang-ro.php +0 -26
  45. PHPMailer/language/phpmailer.lang-rs.php +0 -26
  46. PHPMailer/language/phpmailer.lang-ru.php +0 -27
  47. PHPMailer/language/phpmailer.lang-sk.php +0 -26
  48. PHPMailer/language/phpmailer.lang-sl.php +0 -26
  49. PHPMailer/language/phpmailer.lang-sv.php +0 -26
  50. PHPMailer/language/phpmailer.lang-tr.php +0 -30
  51. PHPMailer/language/phpmailer.lang-uk.php +0 -27
  52. PHPMailer/language/phpmailer.lang-vi.php +0 -26
  53. PHPMailer/language/phpmailer.lang-zh.php +0 -28
  54. PHPMailer/language/phpmailer.lang-zh_cn.php +0 -28
  55. class.phpmaileroauth.php +5 -7
  56. main.php +388 -381
  57. readme.txt +23 -4
PHPMailer/PHPMailerAutoload.php DELETED
@@ -1,51 +0,0 @@
1
- <?php
2
- /**
3
- * PHPMailer SPL autoloader.
4
- * PHP Version 5
5
- * @package PHPMailer
6
- * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
7
- * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
8
- * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
9
- * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
10
- * @author Brent R. Matzelle (original founder)
11
- * @copyright 2012 - 2014 Marcus Bointon
12
- * @copyright 2010 - 2012 Jim Jagielski
13
- * @copyright 2004 - 2009 Andy Prevost
14
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
15
- * @note This program is distributed in the hope that it will be useful - WITHOUT
16
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17
- * FITNESS FOR A PARTICULAR PURPOSE.
18
- */
19
-
20
- /**
21
- * PHPMailer SPL autoloader.
22
- * @param string $classname The name of the class to load
23
- */
24
- function PHPMailerAutoload($classname)
25
- {
26
- //Can't use __DIR__ as it's only in PHP 5.3+
27
- $filename = dirname(__FILE__).DIRECTORY_SEPARATOR.'class.'.strtolower($classname).'.php';
28
- if (is_readable($filename)) {
29
- require $filename;
30
- }
31
- }
32
-
33
- if (version_compare(PHP_VERSION, '5.1.2', '>=')) {
34
- //SPL autoloading was introduced in PHP 5.1.2
35
- if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
36
- spl_autoload_register('PHPMailerAutoload', true, true);
37
- } else {
38
- spl_autoload_register('PHPMailerAutoload');
39
- }
40
- } else {
41
- /**
42
- * Fall back to traditional autoload for old PHP versions
43
- * @param string $classname The name of the class to load
44
- */
45
- /* commented out this code since PHP 7.2 shows a notice even though this part is not getting executed
46
- function __autoload($classname)
47
- {
48
- PHPMailerAutoload($classname);
49
- }
50
- */
51
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
PHPMailer/class.phpmailer.php DELETED
@@ -1,4044 +0,0 @@
1
- <?php
2
- /**
3
- * PHPMailer - PHP email creation and transport class.
4
- * PHP Version 5
5
- * @package PHPMailer
6
- * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
7
- * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
8
- * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
9
- * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
10
- * @author Brent R. Matzelle (original founder)
11
- * @copyright 2012 - 2014 Marcus Bointon
12
- * @copyright 2010 - 2012 Jim Jagielski
13
- * @copyright 2004 - 2009 Andy Prevost
14
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
15
- * @note This program is distributed in the hope that it will be useful - WITHOUT
16
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17
- * FITNESS FOR A PARTICULAR PURPOSE.
18
- */
19
-
20
- /**
21
- * PHPMailer - PHP email creation and transport class.
22
- * @package PHPMailer
23
- * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
24
- * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
25
- * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
26
- * @author Brent R. Matzelle (original founder)
27
- */
28
- class PHPMailer
29
- {
30
- /**
31
- * The PHPMailer Version number.
32
- * @var string
33
- */
34
- public $Version = '5.2.26';
35
-
36
- /**
37
- * Email priority.
38
- * Options: null (default), 1 = High, 3 = Normal, 5 = low.
39
- * When null, the header is not set at all.
40
- * @var integer
41
- */
42
- public $Priority = null;
43
-
44
- /**
45
- * The character set of the message.
46
- * @var string
47
- */
48
- public $CharSet = 'iso-8859-1';
49
-
50
- /**
51
- * The MIME Content-type of the message.
52
- * @var string
53
- */
54
- public $ContentType = 'text/plain';
55
-
56
- /**
57
- * The message encoding.
58
- * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
59
- * @var string
60
- */
61
- public $Encoding = '8bit';
62
-
63
- /**
64
- * Holds the most recent mailer error message.
65
- * @var string
66
- */
67
- public $ErrorInfo = '';
68
-
69
- /**
70
- * The From email address for the message.
71
- * @var string
72
- */
73
- public $From = 'root@localhost';
74
-
75
- /**
76
- * The From name of the message.
77
- * @var string
78
- */
79
- public $FromName = 'Root User';
80
-
81
- /**
82
- * The Sender email (Return-Path) of the message.
83
- * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
84
- * @var string
85
- */
86
- public $Sender = '';
87
-
88
- /**
89
- * The Return-Path of the message.
90
- * If empty, it will be set to either From or Sender.
91
- * @var string
92
- * @deprecated Email senders should never set a return-path header;
93
- * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
94
- * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
95
- */
96
- public $ReturnPath = '';
97
-
98
- /**
99
- * The Subject of the message.
100
- * @var string
101
- */
102
- public $Subject = '';
103
-
104
- /**
105
- * An HTML or plain text message body.
106
- * If HTML then call isHTML(true).
107
- * @var string
108
- */
109
- public $Body = '';
110
-
111
- /**
112
- * The plain-text message body.
113
- * This body can be read by mail clients that do not have HTML email
114
- * capability such as mutt & Eudora.
115
- * Clients that can read HTML will view the normal Body.
116
- * @var string
117
- */
118
- public $AltBody = '';
119
-
120
- /**
121
- * An iCal message part body.
122
- * Only supported in simple alt or alt_inline message types
123
- * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
124
- * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
125
- * @link http://kigkonsult.se/iCalcreator/
126
- * @var string
127
- */
128
- public $Ical = '';
129
-
130
- /**
131
- * The complete compiled MIME message body.
132
- * @access protected
133
- * @var string
134
- */
135
- protected $MIMEBody = '';
136
-
137
- /**
138
- * The complete compiled MIME message headers.
139
- * @var string
140
- * @access protected
141
- */
142
- protected $MIMEHeader = '';
143
-
144
- /**
145
- * Extra headers that createHeader() doesn't fold in.
146
- * @var string
147
- * @access protected
148
- */
149
- protected $mailHeader = '';
150
-
151
- /**
152
- * Word-wrap the message body to this number of chars.
153
- * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
154
- * @var integer
155
- */
156
- public $WordWrap = 0;
157
-
158
- /**
159
- * Which method to use to send mail.
160
- * Options: "mail", "sendmail", or "smtp".
161
- * @var string
162
- */
163
- public $Mailer = 'mail';
164
-
165
- /**
166
- * The path to the sendmail program.
167
- * @var string
168
- */
169
- public $Sendmail = '/usr/sbin/sendmail';
170
-
171
- /**
172
- * Whether mail() uses a fully sendmail-compatible MTA.
173
- * One which supports sendmail's "-oi -f" options.
174
- * @var boolean
175
- */
176
- public $UseSendmailOptions = true;
177
-
178
- /**
179
- * Path to PHPMailer plugins.
180
- * Useful if the SMTP class is not in the PHP include path.
181
- * @var string
182
- * @deprecated Should not be needed now there is an autoloader.
183
- */
184
- public $PluginDir = '';
185
-
186
- /**
187
- * The email address that a reading confirmation should be sent to, also known as read receipt.
188
- * @var string
189
- */
190
- public $ConfirmReadingTo = '';
191
-
192
- /**
193
- * The hostname to use in the Message-ID header and as default HELO string.
194
- * If empty, PHPMailer attempts to find one with, in order,
195
- * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value
196
- * 'localhost.localdomain'.
197
- * @var string
198
- */
199
- public $Hostname = '';
200
-
201
- /**
202
- * An ID to be used in the Message-ID header.
203
- * If empty, a unique id will be generated.
204
- * You can set your own, but it must be in the format "<id@domain>",
205
- * as defined in RFC5322 section 3.6.4 or it will be ignored.
206
- * @see https://tools.ietf.org/html/rfc5322#section-3.6.4
207
- * @var string
208
- */
209
- public $MessageID = '';
210
-
211
- /**
212
- * The message Date to be used in the Date header.
213
- * If empty, the current date will be added.
214
- * @var string
215
- */
216
- public $MessageDate = '';
217
-
218
- /**
219
- * SMTP hosts.
220
- * Either a single hostname or multiple semicolon-delimited hostnames.
221
- * You can also specify a different port
222
- * for each host by using this format: [hostname:port]
223
- * (e.g. "smtp1.example.com:25;smtp2.example.com").
224
- * You can also specify encryption type, for example:
225
- * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
226
- * Hosts will be tried in order.
227
- * @var string
228
- */
229
- public $Host = 'localhost';
230
-
231
- /**
232
- * The default SMTP server port.
233
- * @var integer
234
- * @TODO Why is this needed when the SMTP class takes care of it?
235
- */
236
- public $Port = 25;
237
-
238
- /**
239
- * The SMTP HELO of the message.
240
- * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
241
- * one with the same method described above for $Hostname.
242
- * @var string
243
- * @see PHPMailer::$Hostname
244
- */
245
- public $Helo = '';
246
-
247
- /**
248
- * What kind of encryption to use on the SMTP connection.
249
- * Options: '', 'ssl' or 'tls'
250
- * @var string
251
- */
252
- public $SMTPSecure = '';
253
-
254
- /**
255
- * Whether to enable TLS encryption automatically if a server supports it,
256
- * even if `SMTPSecure` is not set to 'tls'.
257
- * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
258
- * @var boolean
259
- */
260
- public $SMTPAutoTLS = true;
261
-
262
- /**
263
- * Whether to use SMTP authentication.
264
- * Uses the Username and Password properties.
265
- * @var boolean
266
- * @see PHPMailer::$Username
267
- * @see PHPMailer::$Password
268
- */
269
- public $SMTPAuth = false;
270
-
271
- /**
272
- * Options array passed to stream_context_create when connecting via SMTP.
273
- * @var array
274
- */
275
- public $SMTPOptions = array();
276
-
277
- /**
278
- * SMTP username.
279
- * @var string
280
- */
281
- public $Username = '';
282
-
283
- /**
284
- * SMTP password.
285
- * @var string
286
- */
287
- public $Password = '';
288
-
289
- /**
290
- * SMTP auth type.
291
- * Options are CRAM-MD5, LOGIN, PLAIN, NTLM, XOAUTH2, attempted in that order if not specified
292
- * @var string
293
- */
294
- public $AuthType = '';
295
-
296
- /**
297
- * SMTP realm.
298
- * Used for NTLM auth
299
- * @var string
300
- */
301
- public $Realm = '';
302
-
303
- /**
304
- * SMTP workstation.
305
- * Used for NTLM auth
306
- * @var string
307
- */
308
- public $Workstation = '';
309
-
310
- /**
311
- * The SMTP server timeout in seconds.
312
- * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
313
- * @var integer
314
- */
315
- public $Timeout = 300;
316
-
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
- /**
332
- * How to handle debug output.
333
- * Options:
334
- * * `echo` Output plain-text as-is, appropriate for CLI
335
- * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
336
- * * `error_log` Output to error log as configured in php.ini
337
- *
338
- * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
339
- * <code>
340
- * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
341
- * </code>
342
- * @var string|callable
343
- * @see SMTP::$Debugoutput
344
- */
345
- public $Debugoutput = 'echo';
346
-
347
- /**
348
- * Whether to keep SMTP connection open after each message.
349
- * If this is set to true then to close the connection
350
- * requires an explicit call to smtpClose().
351
- * @var boolean
352
- */
353
- public $SMTPKeepAlive = false;
354
-
355
- /**
356
- * Whether to split multiple to addresses into multiple messages
357
- * or send them all in one message.
358
- * Only supported in `mail` and `sendmail` transports, not in SMTP.
359
- * @var boolean
360
- */
361
- public $SingleTo = false;
362
-
363
- /**
364
- * Storage for addresses when SingleTo is enabled.
365
- * @var array
366
- * @TODO This should really not be public
367
- */
368
- public $SingleToArray = array();
369
-
370
- /**
371
- * Whether to generate VERP addresses on send.
372
- * Only applicable when sending via SMTP.
373
- * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
374
- * @link http://www.postfix.org/VERP_README.html Postfix VERP info
375
- * @var boolean
376
- */
377
- public $do_verp = false;
378
-
379
- /**
380
- * Whether to allow sending messages with an empty body.
381
- * @var boolean
382
- */
383
- public $AllowEmpty = false;
384
-
385
- /**
386
- * The default line ending.
387
- * @note The default remains "\n". We force CRLF where we know
388
- * it must be used via self::CRLF.
389
- * @var string
390
- */
391
- public $LE = "\n";
392
-
393
- /**
394
- * DKIM selector.
395
- * @var string
396
- */
397
- public $DKIM_selector = '';
398
-
399
- /**
400
- * DKIM Identity.
401
- * Usually the email address used as the source of the email.
402
- * @var string
403
- */
404
- public $DKIM_identity = '';
405
-
406
- /**
407
- * DKIM passphrase.
408
- * Used if your key is encrypted.
409
- * @var string
410
- */
411
- public $DKIM_passphrase = '';
412
-
413
- /**
414
- * DKIM signing domain name.
415
- * @example 'example.com'
416
- * @var string
417
- */
418
- public $DKIM_domain = '';
419
-
420
- /**
421
- * DKIM private key file path.
422
- * @var string
423
- */
424
- public $DKIM_private = '';
425
-
426
- /**
427
- * DKIM private key string.
428
- * If set, takes precedence over `$DKIM_private`.
429
- * @var string
430
- */
431
- public $DKIM_private_string = '';
432
-
433
- /**
434
- * Callback Action function name.
435
- *
436
- * The function that handles the result of the send email action.
437
- * It is called out by send() for each email sent.
438
- *
439
- * Value can be any php callable: http://www.php.net/is_callable
440
- *
441
- * Parameters:
442
- * boolean $result result of the send action
443
- * array $to email addresses of the recipients
444
- * array $cc cc email addresses
445
- * array $bcc bcc email addresses
446
- * string $subject the subject
447
- * string $body the email body
448
- * string $from email address of sender
449
- * @var string
450
- */
451
- public $action_function = '';
452
-
453
- /**
454
- * What to put in the X-Mailer header.
455
- * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
456
- * @var string
457
- */
458
- public $XMailer = '';
459
-
460
- /**
461
- * Which validator to use by default when validating email addresses.
462
- * May be a callable to inject your own validator, but there are several built-in validators.
463
- * @see PHPMailer::validateAddress()
464
- * @var string|callable
465
- * @static
466
- */
467
- public static $validator = 'auto';
468
-
469
- /**
470
- * An instance of the SMTP sender class.
471
- * @var SMTP
472
- * @access protected
473
- */
474
- protected $smtp = null;
475
-
476
- /**
477
- * The array of 'to' names and addresses.
478
- * @var array
479
- * @access protected
480
- */
481
- protected $to = array();
482
-
483
- /**
484
- * The array of 'cc' names and addresses.
485
- * @var array
486
- * @access protected
487
- */
488
- protected $cc = array();
489
-
490
- /**
491
- * The array of 'bcc' names and addresses.
492
- * @var array
493
- * @access protected
494
- */
495
- protected $bcc = array();
496
-
497
- /**
498
- * The array of reply-to names and addresses.
499
- * @var array
500
- * @access protected
501
- */
502
- protected $ReplyTo = array();
503
-
504
- /**
505
- * An array of all kinds of addresses.
506
- * Includes all of $to, $cc, $bcc
507
- * @var array
508
- * @access protected
509
- * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
510
- */
511
- protected $all_recipients = array();
512
-
513
- /**
514
- * An array of names and addresses queued for validation.
515
- * In send(), valid and non duplicate entries are moved to $all_recipients
516
- * and one of $to, $cc, or $bcc.
517
- * This array is used only for addresses with IDN.
518
- * @var array
519
- * @access protected
520
- * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
521
- * @see PHPMailer::$all_recipients
522
- */
523
- protected $RecipientsQueue = array();
524
-
525
- /**
526
- * An array of reply-to names and addresses queued for validation.
527
- * In send(), valid and non duplicate entries are moved to $ReplyTo.
528
- * This array is used only for addresses with IDN.
529
- * @var array
530
- * @access protected
531
- * @see PHPMailer::$ReplyTo
532
- */
533
- protected $ReplyToQueue = array();
534
-
535
- /**
536
- * The array of attachments.
537
- * @var array
538
- * @access protected
539
- */
540
- protected $attachment = array();
541
-
542
- /**
543
- * The array of custom headers.
544
- * @var array
545
- * @access protected
546
- */
547
- protected $CustomHeader = array();
548
-
549
- /**
550
- * The most recent Message-ID (including angular brackets).
551
- * @var string
552
- * @access protected
553
- */
554
- protected $lastMessageID = '';
555
-
556
- /**
557
- * The message's MIME type.
558
- * @var string
559
- * @access protected
560
- */
561
- protected $message_type = '';
562
-
563
- /**
564
- * The array of MIME boundary strings.
565
- * @var array
566
- * @access protected
567
- */
568
- protected $boundary = array();
569
-
570
- /**
571
- * The array of available languages.
572
- * @var array
573
- * @access protected
574
- */
575
- protected $language = array();
576
-
577
- /**
578
- * The number of errors encountered.
579
- * @var integer
580
- * @access protected
581
- */
582
- protected $error_count = 0;
583
-
584
- /**
585
- * The S/MIME certificate file path.
586
- * @var string
587
- * @access protected
588
- */
589
- protected $sign_cert_file = '';
590
-
591
- /**
592
- * The S/MIME key file path.
593
- * @var string
594
- * @access protected
595
- */
596
- protected $sign_key_file = '';
597
-
598
- /**
599
- * The optional S/MIME extra certificates ("CA Chain") file path.
600
- * @var string
601
- * @access protected
602
- */
603
- protected $sign_extracerts_file = '';
604
-
605
- /**
606
- * The S/MIME password for the key.
607
- * Used only if the key is encrypted.
608
- * @var string
609
- * @access protected
610
- */
611
- protected $sign_key_pass = '';
612
-
613
- /**
614
- * Whether to throw exceptions for errors.
615
- * @var boolean
616
- * @access protected
617
- */
618
- protected $exceptions = false;
619
-
620
- /**
621
- * Unique ID used for message ID and boundaries.
622
- * @var string
623
- * @access protected
624
- */
625
- protected $uniqueid = '';
626
-
627
- /**
628
- * Error severity: message only, continue processing.
629
- */
630
- const STOP_MESSAGE = 0;
631
-
632
- /**
633
- * Error severity: message, likely ok to continue processing.
634
- */
635
- const STOP_CONTINUE = 1;
636
-
637
- /**
638
- * Error severity: message, plus full stop, critical error reached.
639
- */
640
- const STOP_CRITICAL = 2;
641
-
642
- /**
643
- * SMTP RFC standard line ending.
644
- */
645
- const CRLF = "\r\n";
646
-
647
- /**
648
- * The maximum line length allowed by RFC 2822 section 2.1.1
649
- * @var integer
650
- */
651
- const MAX_LINE_LENGTH = 998;
652
-
653
- /**
654
- * Constructor.
655
- * @param boolean $exceptions Should we throw external exceptions?
656
- */
657
- public function __construct($exceptions = null)
658
- {
659
- if ($exceptions !== null) {
660
- $this->exceptions = (boolean)$exceptions;
661
- }
662
- //Pick an appropriate debug output format automatically
663
- $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html');
664
- }
665
-
666
- /**
667
- * Destructor.
668
- */
669
- public function __destruct()
670
- {
671
- //Close any open SMTP connection nicely
672
- $this->smtpClose();
673
- }
674
-
675
- /**
676
- * Call mail() in a safe_mode-aware fashion.
677
- * Also, unless sendmail_path points to sendmail (or something that
678
- * claims to be sendmail), don't pass params (not a perfect fix,
679
- * but it will do)
680
- * @param string $to To
681
- * @param string $subject Subject
682
- * @param string $body Message Body
683
- * @param string $header Additional Header(s)
684
- * @param string $params Params
685
- * @access private
686
- * @return boolean
687
- */
688
- private function mailPassthru($to, $subject, $body, $header, $params)
689
- {
690
- //Check overloading of mail function to avoid double-encoding
691
- if (ini_get('mbstring.func_overload') & 1) {
692
- $subject = $this->secureHeader($subject);
693
- } else {
694
- $subject = $this->encodeHeader($this->secureHeader($subject));
695
- }
696
-
697
- //Can't use additional_parameters in safe_mode, calling mail() with null params breaks
698
- //@link http://php.net/manual/en/function.mail.php
699
- if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
700
- $result = @mail($to, $subject, $body, $header);
701
- } else {
702
- $result = @mail($to, $subject, $body, $header, $params);
703
- }
704
- return $result;
705
- }
706
- /**
707
- * Output debugging info via user-defined method.
708
- * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
709
- * @see PHPMailer::$Debugoutput
710
- * @see PHPMailer::$SMTPDebug
711
- * @param string $str
712
- */
713
- protected function edebug($str)
714
- {
715
- if ($this->SMTPDebug <= 0) {
716
- return;
717
- }
718
- //Avoid clash with built-in function names
719
- if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
720
- call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
721
- return;
722
- }
723
- switch ($this->Debugoutput) {
724
- case 'error_log':
725
- //Don't output, just log
726
- error_log($str);
727
- break;
728
- case 'html':
729
- //Cleans up output a bit for a better looking, HTML-safe output
730
- echo htmlentities(
731
- preg_replace('/[\r\n]+/', '', $str),
732
- ENT_QUOTES,
733
- 'UTF-8'
734
- )
735
- . "<br>\n";
736
- break;
737
- case 'echo':
738
- default:
739
- //Normalize line breaks
740
- $str = preg_replace('/\r\n?/ms', "\n", $str);
741
- echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
742
- "\n",
743
- "\n \t ",
744
- trim($str)
745
- ) . "\n";
746
- }
747
- }
748
-
749
- /**
750
- * Sets message type to HTML or plain.
751
- * @param boolean $isHtml True for HTML mode.
752
- * @return void
753
- */
754
- public function isHTML($isHtml = true)
755
- {
756
- if ($isHtml) {
757
- $this->ContentType = 'text/html';
758
- } else {
759
- $this->ContentType = 'text/plain';
760
- }
761
- }
762
-
763
- /**
764
- * Send messages using SMTP.
765
- * @return void
766
- */
767
- public function isSMTP()
768
- {
769
- $this->Mailer = 'smtp';
770
- }
771
-
772
- /**
773
- * Send messages using PHP's mail() function.
774
- * @return void
775
- */
776
- public function isMail()
777
- {
778
- $this->Mailer = 'mail';
779
- }
780
-
781
- /**
782
- * Send messages using $Sendmail.
783
- * @return void
784
- */
785
- public function isSendmail()
786
- {
787
- $ini_sendmail_path = ini_get('sendmail_path');
788
-
789
- if (!stristr($ini_sendmail_path, 'sendmail')) {
790
- $this->Sendmail = '/usr/sbin/sendmail';
791
- } else {
792
- $this->Sendmail = $ini_sendmail_path;
793
- }
794
- $this->Mailer = 'sendmail';
795
- }
796
-
797
- /**
798
- * Send messages using qmail.
799
- * @return void
800
- */
801
- public function isQmail()
802
- {
803
- $ini_sendmail_path = ini_get('sendmail_path');
804
-
805
- if (!stristr($ini_sendmail_path, 'qmail')) {
806
- $this->Sendmail = '/var/qmail/bin/qmail-inject';
807
- } else {
808
- $this->Sendmail = $ini_sendmail_path;
809
- }
810
- $this->Mailer = 'qmail';
811
- }
812
-
813
- /**
814
- * Add a "To" address.
815
- * @param string $address The email address to send to
816
- * @param string $name
817
- * @return boolean true on success, false if address already used or invalid in some way
818
- */
819
- public function addAddress($address, $name = '')
820
- {
821
- return $this->addOrEnqueueAnAddress('to', $address, $name);
822
- }
823
-
824
- /**
825
- * Add a "CC" address.
826
- * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
827
- * @param string $address The email address to send to
828
- * @param string $name
829
- * @return boolean true on success, false if address already used or invalid in some way
830
- */
831
- public function addCC($address, $name = '')
832
- {
833
- return $this->addOrEnqueueAnAddress('cc', $address, $name);
834
- }
835
-
836
- /**
837
- * Add a "BCC" address.
838
- * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
839
- * @param string $address The email address to send to
840
- * @param string $name
841
- * @return boolean true on success, false if address already used or invalid in some way
842
- */
843
- public function addBCC($address, $name = '')
844
- {
845
- return $this->addOrEnqueueAnAddress('bcc', $address, $name);
846
- }
847
-
848
- /**
849
- * Add a "Reply-To" address.
850
- * @param string $address The email address to reply to
851
- * @param string $name
852
- * @return boolean true on success, false if address already used or invalid in some way
853
- */
854
- public function addReplyTo($address, $name = '')
855
- {
856
- return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
857
- }
858
-
859
- /**
860
- * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
861
- * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
862
- * be modified after calling this function), addition of such addresses is delayed until send().
863
- * Addresses that have been added already return false, but do not throw exceptions.
864
- * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
865
- * @param string $address The email address to send, resp. to reply to
866
- * @param string $name
867
- * @throws phpmailerException
868
- * @return boolean true on success, false if address already used or invalid in some way
869
- * @access protected
870
- */
871
- protected function addOrEnqueueAnAddress($kind, $address, $name)
872
- {
873
- $address = trim($address);
874
- $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
875
- if (($pos = strrpos($address, '@')) === false) {
876
- // At-sign is misssing.
877
- $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
878
- $this->setError($error_message);
879
- $this->edebug($error_message);
880
- if ($this->exceptions) {
881
- throw new phpmailerException($error_message);
882
- }
883
- return false;
884
- }
885
- $params = array($kind, $address, $name);
886
- // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
887
- if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
888
- if ($kind != 'Reply-To') {
889
- if (!array_key_exists($address, $this->RecipientsQueue)) {
890
- $this->RecipientsQueue[$address] = $params;
891
- return true;
892
- }
893
- } else {
894
- if (!array_key_exists($address, $this->ReplyToQueue)) {
895
- $this->ReplyToQueue[$address] = $params;
896
- return true;
897
- }
898
- }
899
- return false;
900
- }
901
- // Immediately add standard addresses without IDN.
902
- return call_user_func_array(array($this, 'addAnAddress'), $params);
903
- }
904
-
905
- /**
906
- * Add an address to one of the recipient arrays or to the ReplyTo array.
907
- * Addresses that have been added already return false, but do not throw exceptions.
908
- * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
909
- * @param string $address The email address to send, resp. to reply to
910
- * @param string $name
911
- * @throws phpmailerException
912
- * @return boolean true on success, false if address already used or invalid in some way
913
- * @access protected
914
- */
915
- protected function addAnAddress($kind, $address, $name = '')
916
- {
917
- if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
918
- $error_message = $this->lang('Invalid recipient kind: ') . $kind;
919
- $this->setError($error_message);
920
- $this->edebug($error_message);
921
- if ($this->exceptions) {
922
- throw new phpmailerException($error_message);
923
- }
924
- return false;
925
- }
926
- if (!$this->validateAddress($address)) {
927
- $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
928
- $this->setError($error_message);
929
- $this->edebug($error_message);
930
- if ($this->exceptions) {
931
- throw new phpmailerException($error_message);
932
- }
933
- return false;
934
- }
935
- if ($kind != 'Reply-To') {
936
- if (!array_key_exists(strtolower($address), $this->all_recipients)) {
937
- array_push($this->$kind, array($address, $name));
938
- $this->all_recipients[strtolower($address)] = true;
939
- return true;
940
- }
941
- } else {
942
- if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
943
- $this->ReplyTo[strtolower($address)] = array($address, $name);
944
- return true;
945
- }
946
- }
947
- return false;
948
- }
949
-
950
- /**
951
- * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
952
- * of the form "display name <address>" into an array of name/address pairs.
953
- * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
954
- * Note that quotes in the name part are removed.
955
- * @param string $addrstr The address list string
956
- * @param bool $useimap Whether to use the IMAP extension to parse the list
957
- * @return array
958
- * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
959
- */
960
- public function parseAddresses($addrstr, $useimap = true)
961
- {
962
- $addresses = array();
963
- if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
964
- //Use this built-in parser if it's available
965
- $list = imap_rfc822_parse_adrlist($addrstr, '');
966
- foreach ($list as $address) {
967
- if ($address->host != '.SYNTAX-ERROR.') {
968
- if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
969
- $addresses[] = array(
970
- 'name' => (property_exists($address, 'personal') ? $address->personal : ''),
971
- 'address' => $address->mailbox . '@' . $address->host
972
- );
973
- }
974
- }
975
- }
976
- } else {
977
- //Use this simpler parser
978
- $list = explode(',', $addrstr);
979
- foreach ($list as $address) {
980
- $address = trim($address);
981
- //Is there a separate name part?
982
- if (strpos($address, '<') === false) {
983
- //No separate name, just use the whole thing
984
- if ($this->validateAddress($address)) {
985
- $addresses[] = array(
986
- 'name' => '',
987
- 'address' => $address
988
- );
989
- }
990
- } else {
991
- list($name, $email) = explode('<', $address);
992
- $email = trim(str_replace('>', '', $email));
993
- if ($this->validateAddress($email)) {
994
- $addresses[] = array(
995
- 'name' => trim(str_replace(array('"', "'"), '', $name)),
996
- 'address' => $email
997
- );
998
- }
999
- }
1000
- }
1001
- }
1002
- return $addresses;
1003
- }
1004
-
1005
- /**
1006
- * Set the From and FromName properties.
1007
- * @param string $address
1008
- * @param string $name
1009
- * @param boolean $auto Whether to also set the Sender address, defaults to true
1010
- * @throws phpmailerException
1011
- * @return boolean
1012
- */
1013
- public function setFrom($address, $name = '', $auto = true)
1014
- {
1015
- $address = trim($address);
1016
- $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
1017
- // Don't validate now addresses with IDN. Will be done in send().
1018
- if (($pos = strrpos($address, '@')) === false or
1019
- (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
1020
- !$this->validateAddress($address)) {
1021
- $error_message = $this->lang('invalid_address') . " (setFrom) $address";
1022
- $this->setError($error_message);
1023
- $this->edebug($error_message);
1024
- if ($this->exceptions) {
1025
- throw new phpmailerException($error_message);
1026
- }
1027
- return false;
1028
- }
1029
- $this->From = $address;
1030
- $this->FromName = $name;
1031
- if ($auto) {
1032
- if (empty($this->Sender)) {
1033
- $this->Sender = $address;
1034
- }
1035
- }
1036
- return true;
1037
- }
1038
-
1039
- /**
1040
- * Return the Message-ID header of the last email.
1041
- * Technically this is the value from the last time the headers were created,
1042
- * but it's also the message ID of the last sent message except in
1043
- * pathological cases.
1044
- * @return string
1045
- */
1046
- public function getLastMessageID()
1047
- {
1048
- return $this->lastMessageID;
1049
- }
1050
-
1051
- /**
1052
- * Check that a string looks like an email address.
1053
- * @param string $address The email address to check
1054
- * @param string|callable $patternselect A selector for the validation pattern to use :
1055
- * * `auto` Pick best pattern automatically;
1056
- * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
1057
- * * `pcre` Use old PCRE implementation;
1058
- * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
1059
- * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
1060
- * * `noregex` Don't use a regex: super fast, really dumb.
1061
- * Alternatively you may pass in a callable to inject your own validator, for example:
1062
- * PHPMailer::validateAddress('user@example.com', function($address) {
1063
- * return (strpos($address, '@') !== false);
1064
- * });
1065
- * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
1066
- * @return boolean
1067
- * @static
1068
- * @access public
1069
- */
1070
- public static function validateAddress($address, $patternselect = null)
1071
- {
1072
- if (is_null($patternselect)) {
1073
- $patternselect = self::$validator;
1074
- }
1075
- if (is_callable($patternselect)) {
1076
- return call_user_func($patternselect, $address);
1077
- }
1078
- //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
1079
- if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
1080
- return false;
1081
- }
1082
- if (!$patternselect or $patternselect == 'auto') {
1083
- //Check this constant first so it works when extension_loaded() is disabled by safe mode
1084
- //Constant was added in PHP 5.2.4
1085
- if (defined('PCRE_VERSION')) {
1086
- //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
1087
- if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
1088
- $patternselect = 'pcre8';
1089
- } else {
1090
- $patternselect = 'pcre';
1091
- }
1092
- } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
1093
- //Fall back to older PCRE
1094
- $patternselect = 'pcre';
1095
- } else {
1096
- //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
1097
- if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
1098
- $patternselect = 'php';
1099
- } else {
1100
- $patternselect = 'noregex';
1101
- }
1102
- }
1103
- }
1104
- switch ($patternselect) {
1105
- case 'pcre8':
1106
- /**
1107
- * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
1108
- * @link http://squiloople.com/2009/12/20/email-address-validation/
1109
- * @copyright 2009-2010 Michael Rushton
1110
- * Feel free to use and redistribute this code. But please keep this copyright notice.
1111
- */
1112
- return (boolean)preg_match(
1113
- '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
1114
- '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
1115
- '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
1116
- '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
1117
- '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
1118
- '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
1119
- '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
1120
- '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1121
- '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
1122
- $address
1123
- );
1124
- case 'pcre':
1125
- //An older regex that doesn't need a recent PCRE
1126
- return (boolean)preg_match(
1127
- '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
1128
- '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
1129
- '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
1130
- '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
1131
- '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
1132
- '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
1133
- '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
1134
- '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
1135
- '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1136
- '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
1137
- $address
1138
- );
1139
- case 'html5':
1140
- /**
1141
- * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
1142
- * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
1143
- */
1144
- return (boolean)preg_match(
1145
- '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
1146
- '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
1147
- $address
1148
- );
1149
- case 'noregex':
1150
- //No PCRE! Do something _very_ approximate!
1151
- //Check the address is 3 chars or longer and contains an @ that's not the first or last char
1152
- return (strlen($address) >= 3
1153
- and strpos($address, '@') >= 1
1154
- and strpos($address, '@') != strlen($address) - 1);
1155
- case 'php':
1156
- default:
1157
- return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
1158
- }
1159
- }
1160
-
1161
- /**
1162
- * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
1163
- * "intl" and "mbstring" PHP extensions.
1164
- * @return bool "true" if required functions for IDN support are present
1165
- */
1166
- public function idnSupported()
1167
- {
1168
- // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
1169
- return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
1170
- }
1171
-
1172
- /**
1173
- * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
1174
- * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
1175
- * This function silently returns unmodified address if:
1176
- * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
1177
- * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
1178
- * or fails for any reason (e.g. domain has characters not allowed in an IDN)
1179
- * @see PHPMailer::$CharSet
1180
- * @param string $address The email address to convert
1181
- * @return string The encoded address in ASCII form
1182
- */
1183
- public function punyencodeAddress($address)
1184
- {
1185
- // Verify we have required functions, CharSet, and at-sign.
1186
- if ($this->idnSupported() and
1187
- !empty($this->CharSet) and
1188
- ($pos = strrpos($address, '@')) !== false) {
1189
- $domain = substr($address, ++$pos);
1190
- // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
1191
- if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
1192
- $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
1193
- if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
1194
- idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
1195
- idn_to_ascii($domain)) !== false) {
1196
- return substr($address, 0, $pos) . $punycode;
1197
- }
1198
- }
1199
- }
1200
- return $address;
1201
- }
1202
-
1203
- /**
1204
- * Create a message and send it.
1205
- * Uses the sending method specified by $Mailer.
1206
- * @throws phpmailerException
1207
- * @return boolean false on error - See the ErrorInfo property for details of the error.
1208
- */
1209
- public function send()
1210
- {
1211
- try {
1212
- if (!$this->preSend()) {
1213
- return false;
1214
- }
1215
- return $this->postSend();
1216
- } catch (phpmailerException $exc) {
1217
- $this->mailHeader = '';
1218
- $this->setError($exc->getMessage());
1219
- if ($this->exceptions) {
1220
- throw $exc;
1221
- }
1222
- return false;
1223
- }
1224
- }
1225
-
1226
- /**
1227
- * Prepare a message for sending.
1228
- * @throws phpmailerException
1229
- * @return boolean
1230
- */
1231
- public function preSend()
1232
- {
1233
- try {
1234
- $this->error_count = 0; // Reset errors
1235
- $this->mailHeader = '';
1236
-
1237
- // Dequeue recipient and Reply-To addresses with IDN
1238
- foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
1239
- $params[1] = $this->punyencodeAddress($params[1]);
1240
- call_user_func_array(array($this, 'addAnAddress'), $params);
1241
- }
1242
- if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
1243
- throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
1244
- }
1245
-
1246
- // Validate From, Sender, and ConfirmReadingTo addresses
1247
- foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
1248
- $this->$address_kind = trim($this->$address_kind);
1249
- if (empty($this->$address_kind)) {
1250
- continue;
1251
- }
1252
- $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
1253
- if (!$this->validateAddress($this->$address_kind)) {
1254
- $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
1255
- $this->setError($error_message);
1256
- $this->edebug($error_message);
1257
- if ($this->exceptions) {
1258
- throw new phpmailerException($error_message);
1259
- }
1260
- return false;
1261
- }
1262
- }
1263
-
1264
- // Set whether the message is multipart/alternative
1265
- if ($this->alternativeExists()) {
1266
- $this->ContentType = 'multipart/alternative';
1267
- }
1268
-
1269
- $this->setMessageType();
1270
- // Refuse to send an empty message unless we are specifically allowing it
1271
- if (!$this->AllowEmpty and empty($this->Body)) {
1272
- throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
1273
- }
1274
-
1275
- // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
1276
- $this->MIMEHeader = '';
1277
- $this->MIMEBody = $this->createBody();
1278
- // createBody may have added some headers, so retain them
1279
- $tempheaders = $this->MIMEHeader;
1280
- $this->MIMEHeader = $this->createHeader();
1281
- $this->MIMEHeader .= $tempheaders;
1282
-
1283
- // To capture the complete message when using mail(), create
1284
- // an extra header list which createHeader() doesn't fold in
1285
- if ($this->Mailer == 'mail') {
1286
- if (count($this->to) > 0) {
1287
- $this->mailHeader .= $this->addrAppend('To', $this->to);
1288
- } else {
1289
- $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
1290
- }
1291
- $this->mailHeader .= $this->headerLine(
1292
- 'Subject',
1293
- $this->encodeHeader($this->secureHeader(trim($this->Subject)))
1294
- );
1295
- }
1296
-
1297
- // Sign with DKIM if enabled
1298
- if (!empty($this->DKIM_domain)
1299
- && !empty($this->DKIM_selector)
1300
- && (!empty($this->DKIM_private_string)
1301
- || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
1302
- )
1303
- ) {
1304
- $header_dkim = $this->DKIM_Add(
1305
- $this->MIMEHeader . $this->mailHeader,
1306
- $this->encodeHeader($this->secureHeader($this->Subject)),
1307
- $this->MIMEBody
1308
- );
1309
- $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
1310
- str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
1311
- }
1312
- return true;
1313
- } catch (phpmailerException $exc) {
1314
- $this->setError($exc->getMessage());
1315
- if ($this->exceptions) {
1316
- throw $exc;
1317
- }
1318
- return false;
1319
- }
1320
- }
1321
-
1322
- /**
1323
- * Actually send a message.
1324
- * Send the email via the selected mechanism
1325
- * @throws phpmailerException
1326
- * @return boolean
1327
- */
1328
- public function postSend()
1329
- {
1330
- try {
1331
- // Choose the mailer and send through it
1332
- switch ($this->Mailer) {
1333
- case 'sendmail':
1334
- case 'qmail':
1335
- return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
1336
- case 'smtp':
1337
- return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
1338
- case 'mail':
1339
- return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1340
- default:
1341
- $sendMethod = $this->Mailer.'Send';
1342
- if (method_exists($this, $sendMethod)) {
1343
- return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
1344
- }
1345
-
1346
- return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1347
- }
1348
- } catch (phpmailerException $exc) {
1349
- $this->setError($exc->getMessage());
1350
- $this->edebug($exc->getMessage());
1351
- if ($this->exceptions) {
1352
- throw $exc;
1353
- }
1354
- }
1355
- return false;
1356
- }
1357
-
1358
- /**
1359
- * Send mail using the $Sendmail program.
1360
- * @param string $header The message headers
1361
- * @param string $body The message body
1362
- * @see PHPMailer::$Sendmail
1363
- * @throws phpmailerException
1364
- * @access protected
1365
- * @return boolean
1366
- */
1367
- protected function sendmailSend($header, $body)
1368
- {
1369
- // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1370
- if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
1371
- if ($this->Mailer == 'qmail') {
1372
- $sendmailFmt = '%s -f%s';
1373
- } else {
1374
- $sendmailFmt = '%s -oi -f%s -t';
1375
- }
1376
- } else {
1377
- if ($this->Mailer == 'qmail') {
1378
- $sendmailFmt = '%s';
1379
- } else {
1380
- $sendmailFmt = '%s -oi -t';
1381
- }
1382
- }
1383
-
1384
- // TODO: If possible, this should be changed to escapeshellarg. Needs thorough testing.
1385
- $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
1386
-
1387
- if ($this->SingleTo) {
1388
- foreach ($this->SingleToArray as $toAddr) {
1389
- if (!@$mail = popen($sendmail, 'w')) {
1390
- throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1391
- }
1392
- fputs($mail, 'To: ' . $toAddr . "\n");
1393
- fputs($mail, $header);
1394
- fputs($mail, $body);
1395
- $result = pclose($mail);
1396
- $this->doCallback(
1397
- ($result == 0),
1398
- array($toAddr),
1399
- $this->cc,
1400
- $this->bcc,
1401
- $this->Subject,
1402
- $body,
1403
- $this->From
1404
- );
1405
- if ($result != 0) {
1406
- throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1407
- }
1408
- }
1409
- } else {
1410
- if (!@$mail = popen($sendmail, 'w')) {
1411
- throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1412
- }
1413
- fputs($mail, $header);
1414
- fputs($mail, $body);
1415
- $result = pclose($mail);
1416
- $this->doCallback(
1417
- ($result == 0),
1418
- $this->to,
1419
- $this->cc,
1420
- $this->bcc,
1421
- $this->Subject,
1422
- $body,
1423
- $this->From
1424
- );
1425
- if ($result != 0) {
1426
- throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1427
- }
1428
- }
1429
- return true;
1430
- }
1431
-
1432
- /**
1433
- * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
1434
- *
1435
- * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
1436
- * @param string $string The string to be validated
1437
- * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
1438
- * @access protected
1439
- * @return boolean
1440
- */
1441
- protected static function isShellSafe($string)
1442
- {
1443
- // Future-proof
1444
- if (escapeshellcmd($string) !== $string
1445
- or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))
1446
- ) {
1447
- return false;
1448
- }
1449
-
1450
- $length = strlen($string);
1451
-
1452
- for ($i = 0; $i < $length; $i++) {
1453
- $c = $string[$i];
1454
-
1455
- // All other characters have a special meaning in at least one common shell, including = and +.
1456
- // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
1457
- // Note that this does permit non-Latin alphanumeric characters based on the current locale.
1458
- if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
1459
- return false;
1460
- }
1461
- }
1462
-
1463
- return true;
1464
- }
1465
-
1466
- /**
1467
- * Send mail using the PHP mail() function.
1468
- * @param string $header The message headers
1469
- * @param string $body The message body
1470
- * @link http://www.php.net/manual/en/book.mail.php
1471
- * @throws phpmailerException
1472
- * @access protected
1473
- * @return boolean
1474
- */
1475
- protected function mailSend($header, $body)
1476
- {
1477
- $toArr = array();
1478
- foreach ($this->to as $toaddr) {
1479
- $toArr[] = $this->addrFormat($toaddr);
1480
- }
1481
- $to = implode(', ', $toArr);
1482
-
1483
- $params = null;
1484
- //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
1485
- if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
1486
- // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1487
- if (self::isShellSafe($this->Sender)) {
1488
- $params = sprintf('-f%s', $this->Sender);
1489
- }
1490
- }
1491
- if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {
1492
- $old_from = ini_get('sendmail_from');
1493
- ini_set('sendmail_from', $this->Sender);
1494
- }
1495
- $result = false;
1496
- if ($this->SingleTo and count($toArr) > 1) {
1497
- foreach ($toArr as $toAddr) {
1498
- $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
1499
- $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1500
- }
1501
- } else {
1502
- $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
1503
- $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1504
- }
1505
- if (isset($old_from)) {
1506
- ini_set('sendmail_from', $old_from);
1507
- }
1508
- if (!$result) {
1509
- throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
1510
- }
1511
- return true;
1512
- }
1513
-
1514
- /**
1515
- * Get an instance to use for SMTP operations.
1516
- * Override this function to load your own SMTP implementation
1517
- * @return SMTP
1518
- */
1519
- public function getSMTPInstance()
1520
- {
1521
- if (!is_object($this->smtp)) {
1522
- $this->smtp = new SMTP;
1523
- }
1524
- return $this->smtp;
1525
- }
1526
-
1527
- /**
1528
- * Send mail via SMTP.
1529
- * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
1530
- * Uses the PHPMailerSMTP class by default.
1531
- * @see PHPMailer::getSMTPInstance() to use a different class.
1532
- * @param string $header The message headers
1533
- * @param string $body The message body
1534
- * @throws phpmailerException
1535
- * @uses SMTP
1536
- * @access protected
1537
- * @return boolean
1538
- */
1539
- protected function smtpSend($header, $body)
1540
- {
1541
- $bad_rcpt = array();
1542
- if (!$this->smtpConnect($this->SMTPOptions)) {
1543
- throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
1544
- }
1545
- if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
1546
- $smtp_from = $this->Sender;
1547
- } else {
1548
- $smtp_from = $this->From;
1549
- }
1550
- if (!$this->smtp->mail($smtp_from)) {
1551
- $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
1552
- throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
1553
- }
1554
-
1555
- // Attempt to send to all recipients
1556
- foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
1557
- foreach ($togroup as $to) {
1558
- if (!$this->smtp->recipient($to[0])) {
1559
- $error = $this->smtp->getError();
1560
- $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
1561
- $isSent = false;
1562
- } else {
1563
- $isSent = true;
1564
- }
1565
- $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
1566
- }
1567
- }
1568
-
1569
- // Only send the DATA command if we have viable recipients
1570
- if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
1571
- throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
1572
- }
1573
- if ($this->SMTPKeepAlive) {
1574
- $this->smtp->reset();
1575
- } else {
1576
- $this->smtp->quit();
1577
- $this->smtp->close();
1578
- }
1579
- //Create error message for any bad addresses
1580
- if (count($bad_rcpt) > 0) {
1581
- $errstr = '';
1582
- foreach ($bad_rcpt as $bad) {
1583
- $errstr .= $bad['to'] . ': ' . $bad['error'];
1584
- }
1585
- throw new phpmailerException(
1586
- $this->lang('recipients_failed') . $errstr,
1587
- self::STOP_CONTINUE
1588
- );
1589
- }
1590
- return true;
1591
- }
1592
-
1593
- /**
1594
- * Initiate a connection to an SMTP server.
1595
- * Returns false if the operation failed.
1596
- * @param array $options An array of options compatible with stream_context_create()
1597
- * @uses SMTP
1598
- * @access public
1599
- * @throws phpmailerException
1600
- * @return boolean
1601
- */
1602
- public function smtpConnect($options = null)
1603
- {
1604
- if (is_null($this->smtp)) {
1605
- $this->smtp = $this->getSMTPInstance();
1606
- }
1607
-
1608
- //If no options are provided, use whatever is set in the instance
1609
- if (is_null($options)) {
1610
- $options = $this->SMTPOptions;
1611
- }
1612
-
1613
- // Already connected?
1614
- if ($this->smtp->connected()) {
1615
- return true;
1616
- }
1617
-
1618
- $this->smtp->setTimeout($this->Timeout);
1619
- $this->smtp->setDebugLevel($this->SMTPDebug);
1620
- $this->smtp->setDebugOutput($this->Debugoutput);
1621
- $this->smtp->setVerp($this->do_verp);
1622
- $hosts = explode(';', $this->Host);
1623
- $lastexception = null;
1624
-
1625
- foreach ($hosts as $hostentry) {
1626
- $hostinfo = array();
1627
- if (!preg_match(
1628
- '/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*|\[[a-fA-F0-9:]+\]):?([0-9]*)$/',
1629
- trim($hostentry),
1630
- $hostinfo
1631
- )) {
1632
- // Not a valid host entry
1633
- $this->edebug('Ignoring invalid host: ' . $hostentry);
1634
- continue;
1635
- }
1636
- // $hostinfo[2]: optional ssl or tls prefix
1637
- // $hostinfo[3]: the hostname
1638
- // $hostinfo[4]: optional port number
1639
- // The host string prefix can temporarily override the current setting for SMTPSecure
1640
- // If it's not specified, the default value is used
1641
- $prefix = '';
1642
- $secure = $this->SMTPSecure;
1643
- $tls = ($this->SMTPSecure == 'tls');
1644
- if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
1645
- $prefix = 'ssl://';
1646
- $tls = false; // Can't have SSL and TLS at the same time
1647
- $secure = 'ssl';
1648
- } elseif ($hostinfo[2] == 'tls') {
1649
- $tls = true;
1650
- // tls doesn't use a prefix
1651
- $secure = 'tls';
1652
- }
1653
- //Do we need the OpenSSL extension?
1654
- $sslext = defined('OPENSSL_ALGO_SHA1');
1655
- if ('tls' === $secure or 'ssl' === $secure) {
1656
- //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
1657
- if (!$sslext) {
1658
- throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
1659
- }
1660
- }
1661
- $host = $hostinfo[3];
1662
- $port = $this->Port;
1663
- $tport = (integer)$hostinfo[4];
1664
- if ($tport > 0 and $tport < 65536) {
1665
- $port = $tport;
1666
- }
1667
- if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
1668
- try {
1669
- if ($this->Helo) {
1670
- $hello = $this->Helo;
1671
- } else {
1672
- $hello = $this->serverHostname();
1673
- }
1674
- $this->smtp->hello($hello);
1675
- //Automatically enable TLS encryption if:
1676
- // * it's not disabled
1677
- // * we have openssl extension
1678
- // * we are not already using SSL
1679
- // * the server offers STARTTLS
1680
- if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
1681
- $tls = true;
1682
- }
1683
- if ($tls) {
1684
- if (!$this->smtp->startTLS()) {
1685
- throw new phpmailerException($this->lang('connect_host'));
1686
- }
1687
- // We must resend EHLO after TLS negotiation
1688
- $this->smtp->hello($hello);
1689
- }
1690
- if ($this->SMTPAuth) {
1691
- if (!$this->smtp->authenticate(
1692
- $this->Username,
1693
- $this->Password,
1694
- $this->AuthType,
1695
- $this->Realm,
1696
- $this->Workstation
1697
- )
1698
- ) {
1699
- throw new phpmailerException($this->lang('authenticate'));
1700
- }
1701
- }
1702
- return true;
1703
- } catch (phpmailerException $exc) {
1704
- $lastexception = $exc;
1705
- $this->edebug($exc->getMessage());
1706
- // We must have connected, but then failed TLS or Auth, so close connection nicely
1707
- $this->smtp->quit();
1708
- }
1709
- }
1710
- }
1711
- // If we get here, all connection attempts have failed, so close connection hard
1712
- $this->smtp->close();
1713
- // As we've caught all exceptions, just report whatever the last one was
1714
- if ($this->exceptions and !is_null($lastexception)) {
1715
- throw $lastexception;
1716
- }
1717
- return false;
1718
- }
1719
-
1720
- /**
1721
- * Close the active SMTP session if one exists.
1722
- * @return void
1723
- */
1724
- public function smtpClose()
1725
- {
1726
- if (is_a($this->smtp, 'SMTP')) {
1727
- if ($this->smtp->connected()) {
1728
- $this->smtp->quit();
1729
- $this->smtp->close();
1730
- }
1731
- }
1732
- }
1733
-
1734
- /**
1735
- * Set the language for error messages.
1736
- * Returns false if it cannot load the language file.
1737
- * The default language is English.
1738
- * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
1739
- * @param string $lang_path Path to the language file directory, with trailing separator (slash)
1740
- * @return boolean
1741
- * @access public
1742
- */
1743
- public function setLanguage($langcode = 'en', $lang_path = '')
1744
- {
1745
- // Backwards compatibility for renamed language codes
1746
- $renamed_langcodes = array(
1747
- 'br' => 'pt_br',
1748
- 'cz' => 'cs',
1749
- 'dk' => 'da',
1750
- 'no' => 'nb',
1751
- 'se' => 'sv',
1752
- 'sr' => 'rs'
1753
- );
1754
-
1755
- if (isset($renamed_langcodes[$langcode])) {
1756
- $langcode = $renamed_langcodes[$langcode];
1757
- }
1758
-
1759
- // Define full set of translatable strings in English
1760
- $PHPMAILER_LANG = array(
1761
- 'authenticate' => 'SMTP Error: Could not authenticate.',
1762
- 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
1763
- 'data_not_accepted' => 'SMTP Error: data not accepted.',
1764
- 'empty_message' => 'Message body empty',
1765
- 'encoding' => 'Unknown encoding: ',
1766
- 'execute' => 'Could not execute: ',
1767
- 'file_access' => 'Could not access file: ',
1768
- 'file_open' => 'File Error: Could not open file: ',
1769
- 'from_failed' => 'The following From address failed: ',
1770
- 'instantiate' => 'Could not instantiate mail function.',
1771
- 'invalid_address' => 'Invalid address: ',
1772
- 'mailer_not_supported' => ' mailer is not supported.',
1773
- 'provide_address' => 'You must provide at least one recipient email address.',
1774
- 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
1775
- 'signing' => 'Signing Error: ',
1776
- 'smtp_connect_failed' => 'SMTP connect() failed.',
1777
- 'smtp_error' => 'SMTP server error: ',
1778
- 'variable_set' => 'Cannot set or reset variable: ',
1779
- 'extension_missing' => 'Extension missing: '
1780
- );
1781
- if (empty($lang_path)) {
1782
- // Calculate an absolute path so it can work if CWD is not here
1783
- $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
1784
- }
1785
- //Validate $langcode
1786
- if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
1787
- $langcode = 'en';
1788
- }
1789
- $foundlang = true;
1790
- $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
1791
- // There is no English translation file
1792
- if ($langcode != 'en') {
1793
- // Make sure language file path is readable
1794
- if (!is_readable($lang_file)) {
1795
- $foundlang = false;
1796
- } else {
1797
- // Overwrite language-specific strings.
1798
- // This way we'll never have missing translation keys.
1799
- $foundlang = include $lang_file;
1800
- }
1801
- }
1802
- $this->language = $PHPMAILER_LANG;
1803
- return (boolean)$foundlang; // Returns false if language not found
1804
- }
1805
-
1806
- /**
1807
- * Get the array of strings for the current language.
1808
- * @return array
1809
- */
1810
- public function getTranslations()
1811
- {
1812
- return $this->language;
1813
- }
1814
-
1815
- /**
1816
- * Create recipient headers.
1817
- * @access public
1818
- * @param string $type
1819
- * @param array $addr An array of recipient,
1820
- * where each recipient is a 2-element indexed array with element 0 containing an address
1821
- * and element 1 containing a name, like:
1822
- * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
1823
- * @return string
1824
- */
1825
- public function addrAppend($type, $addr)
1826
- {
1827
- $addresses = array();
1828
- foreach ($addr as $address) {
1829
- $addresses[] = $this->addrFormat($address);
1830
- }
1831
- return $type . ': ' . implode(', ', $addresses) . $this->LE;
1832
- }
1833
-
1834
- /**
1835
- * Format an address for use in a message header.
1836
- * @access public
1837
- * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
1838
- * like array('joe@example.com', 'Joe User')
1839
- * @return string
1840
- */
1841
- public function addrFormat($addr)
1842
- {
1843
- if (empty($addr[1])) { // No name provided
1844
- return $this->secureHeader($addr[0]);
1845
- } else {
1846
- return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
1847
- $addr[0]
1848
- ) . '>';
1849
- }
1850
- }
1851
-
1852
- /**
1853
- * Word-wrap message.
1854
- * For use with mailers that do not automatically perform wrapping
1855
- * and for quoted-printable encoded messages.
1856
- * Original written by philippe.
1857
- * @param string $message The message to wrap
1858
- * @param integer $length The line length to wrap to
1859
- * @param boolean $qp_mode Whether to run in Quoted-Printable mode
1860
- * @access public
1861
- * @return string
1862
- */
1863
- public function wrapText($message, $length, $qp_mode = false)
1864
- {
1865
- if ($qp_mode) {
1866
- $soft_break = sprintf(' =%s', $this->LE);
1867
- } else {
1868
- $soft_break = $this->LE;
1869
- }
1870
- // If utf-8 encoding is used, we will need to make sure we don't
1871
- // split multibyte characters when we wrap
1872
- $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
1873
- $lelen = strlen($this->LE);
1874
- $crlflen = strlen(self::CRLF);
1875
-
1876
- $message = $this->fixEOL($message);
1877
- //Remove a trailing line break
1878
- if (substr($message, -$lelen) == $this->LE) {
1879
- $message = substr($message, 0, -$lelen);
1880
- }
1881
-
1882
- //Split message into lines
1883
- $lines = explode($this->LE, $message);
1884
- //Message will be rebuilt in here
1885
- $message = '';
1886
- foreach ($lines as $line) {
1887
- $words = explode(' ', $line);
1888
- $buf = '';
1889
- $firstword = true;
1890
- foreach ($words as $word) {
1891
- if ($qp_mode and (strlen($word) > $length)) {
1892
- $space_left = $length - strlen($buf) - $crlflen;
1893
- if (!$firstword) {
1894
- if ($space_left > 20) {
1895
- $len = $space_left;
1896
- if ($is_utf8) {
1897
- $len = $this->utf8CharBoundary($word, $len);
1898
- } elseif (substr($word, $len - 1, 1) == '=') {
1899
- $len--;
1900
- } elseif (substr($word, $len - 2, 1) == '=') {
1901
- $len -= 2;
1902
- }
1903
- $part = substr($word, 0, $len);
1904
- $word = substr($word, $len);
1905
- $buf .= ' ' . $part;
1906
- $message .= $buf . sprintf('=%s', self::CRLF);
1907
- } else {
1908
- $message .= $buf . $soft_break;
1909
- }
1910
- $buf = '';
1911
- }
1912
- while (strlen($word) > 0) {
1913
- if ($length <= 0) {
1914
- break;
1915
- }
1916
- $len = $length;
1917
- if ($is_utf8) {
1918
- $len = $this->utf8CharBoundary($word, $len);
1919
- } elseif (substr($word, $len - 1, 1) == '=') {
1920
- $len--;
1921
- } elseif (substr($word, $len - 2, 1) == '=') {
1922
- $len -= 2;
1923
- }
1924
- $part = substr($word, 0, $len);
1925
- $word = substr($word, $len);
1926
-
1927
- if (strlen($word) > 0) {
1928
- $message .= $part . sprintf('=%s', self::CRLF);
1929
- } else {
1930
- $buf = $part;
1931
- }
1932
- }
1933
- } else {
1934
- $buf_o = $buf;
1935
- if (!$firstword) {
1936
- $buf .= ' ';
1937
- }
1938
- $buf .= $word;
1939
-
1940
- if (strlen($buf) > $length and $buf_o != '') {
1941
- $message .= $buf_o . $soft_break;
1942
- $buf = $word;
1943
- }
1944
- }
1945
- $firstword = false;
1946
- }
1947
- $message .= $buf . self::CRLF;
1948
- }
1949
-
1950
- return $message;
1951
- }
1952
-
1953
- /**
1954
- * Find the last character boundary prior to $maxLength in a utf-8
1955
- * quoted-printable encoded string.
1956
- * Original written by Colin Brown.
1957
- * @access public
1958
- * @param string $encodedText utf-8 QP text
1959
- * @param integer $maxLength Find the last character boundary prior to this length
1960
- * @return integer
1961
- */
1962
- public function utf8CharBoundary($encodedText, $maxLength)
1963
- {
1964
- $foundSplitPos = false;
1965
- $lookBack = 3;
1966
- while (!$foundSplitPos) {
1967
- $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1968
- $encodedCharPos = strpos($lastChunk, '=');
1969
- if (false !== $encodedCharPos) {
1970
- // Found start of encoded character byte within $lookBack block.
1971
- // Check the encoded byte value (the 2 chars after the '=')
1972
- $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1973
- $dec = hexdec($hex);
1974
- if ($dec < 128) {
1975
- // Single byte character.
1976
- // If the encoded char was found at pos 0, it will fit
1977
- // otherwise reduce maxLength to start of the encoded char
1978
- if ($encodedCharPos > 0) {
1979
- $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1980
- }
1981
- $foundSplitPos = true;
1982
- } elseif ($dec >= 192) {
1983
- // First byte of a multi byte character
1984
- // Reduce maxLength to split at start of character
1985
- $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1986
- $foundSplitPos = true;
1987
- } elseif ($dec < 192) {
1988
- // Middle byte of a multi byte character, look further back
1989
- $lookBack += 3;
1990
- }
1991
- } else {
1992
- // No encoded character found
1993
- $foundSplitPos = true;
1994
- }
1995
- }
1996
- return $maxLength;
1997
- }
1998
-
1999
- /**
2000
- * Apply word wrapping to the message body.
2001
- * Wraps the message body to the number of chars set in the WordWrap property.
2002
- * You should only do this to plain-text bodies as wrapping HTML tags may break them.
2003
- * This is called automatically by createBody(), so you don't need to call it yourself.
2004
- * @access public
2005
- * @return void
2006
- */
2007
- public function setWordWrap()
2008
- {
2009
- if ($this->WordWrap < 1) {
2010
- return;
2011
- }
2012
-
2013
- switch ($this->message_type) {
2014
- case 'alt':
2015
- case 'alt_inline':
2016
- case 'alt_attach':
2017
- case 'alt_inline_attach':
2018
- $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
2019
- break;
2020
- default:
2021
- $this->Body = $this->wrapText($this->Body, $this->WordWrap);
2022
- break;
2023
- }
2024
- }
2025
-
2026
- /**
2027
- * Assemble message headers.
2028
- * @access public
2029
- * @return string The assembled headers
2030
- */
2031
- public function createHeader()
2032
- {
2033
- $result = '';
2034
-
2035
- $result .= $this->headerLine('Date', $this->MessageDate == '' ? self::rfcDate() : $this->MessageDate);
2036
-
2037
- // To be created automatically by mail()
2038
- if ($this->SingleTo) {
2039
- if ($this->Mailer != 'mail') {
2040
- foreach ($this->to as $toaddr) {
2041
- $this->SingleToArray[] = $this->addrFormat($toaddr);
2042
- }
2043
- }
2044
- } else {
2045
- if (count($this->to) > 0) {
2046
- if ($this->Mailer != 'mail') {
2047
- $result .= $this->addrAppend('To', $this->to);
2048
- }
2049
- } elseif (count($this->cc) == 0) {
2050
- $result .= $this->headerLine('To', 'undisclosed-recipients:;');
2051
- }
2052
- }
2053
-
2054
- $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
2055
-
2056
- // sendmail and mail() extract Cc from the header before sending
2057
- if (count($this->cc) > 0) {
2058
- $result .= $this->addrAppend('Cc', $this->cc);
2059
- }
2060
-
2061
- // sendmail and mail() extract Bcc from the header before sending
2062
- if ((
2063
- $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
2064
- )
2065
- and count($this->bcc) > 0
2066
- ) {
2067
- $result .= $this->addrAppend('Bcc', $this->bcc);
2068
- }
2069
-
2070
- if (count($this->ReplyTo) > 0) {
2071
- $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
2072
- }
2073
-
2074
- // mail() sets the subject itself
2075
- if ($this->Mailer != 'mail') {
2076
- $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
2077
- }
2078
-
2079
- // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
2080
- // https://tools.ietf.org/html/rfc5322#section-3.6.4
2081
- if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
2082
- $this->lastMessageID = $this->MessageID;
2083
- } else {
2084
- $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
2085
- }
2086
- $result .= $this->headerLine('Message-ID', $this->lastMessageID);
2087
- if (!is_null($this->Priority)) {
2088
- $result .= $this->headerLine('X-Priority', $this->Priority);
2089
- }
2090
- if ($this->XMailer == '') {
2091
- $result .= $this->headerLine(
2092
- 'X-Mailer',
2093
- 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
2094
- );
2095
- } else {
2096
- $myXmailer = trim($this->XMailer);
2097
- if ($myXmailer) {
2098
- $result .= $this->headerLine('X-Mailer', $myXmailer);
2099
- }
2100
- }
2101
-
2102
- if ($this->ConfirmReadingTo != '') {
2103
- $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
2104
- }
2105
-
2106
- // Add custom headers
2107
- foreach ($this->CustomHeader as $header) {
2108
- $result .= $this->headerLine(
2109
- trim($header[0]),
2110
- $this->encodeHeader(trim($header[1]))
2111
- );
2112
- }
2113
- if (!$this->sign_key_file) {
2114
- $result .= $this->headerLine('MIME-Version', '1.0');
2115
- $result .= $this->getMailMIME();
2116
- }
2117
-
2118
- return $result;
2119
- }
2120
-
2121
- /**
2122
- * Get the message MIME type headers.
2123
- * @access public
2124
- * @return string
2125
- */
2126
- public function getMailMIME()
2127
- {
2128
- $result = '';
2129
- $ismultipart = true;
2130
- switch ($this->message_type) {
2131
- case 'inline':
2132
- $result .= $this->headerLine('Content-Type', 'multipart/related;');
2133
- $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2134
- break;
2135
- case 'attach':
2136
- case 'inline_attach':
2137
- case 'alt_attach':
2138
- case 'alt_inline_attach':
2139
- $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
2140
- $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2141
- break;
2142
- case 'alt':
2143
- case 'alt_inline':
2144
- $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
2145
- $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2146
- break;
2147
- default:
2148
- // Catches case 'plain': and case '':
2149
- $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
2150
- $ismultipart = false;
2151
- break;
2152
- }
2153
- // RFC1341 part 5 says 7bit is assumed if not specified
2154
- if ($this->Encoding != '7bit') {
2155
- // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
2156
- if ($ismultipart) {
2157
- if ($this->Encoding == '8bit') {
2158
- $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
2159
- }
2160
- // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
2161
- } else {
2162
- $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
2163
- }
2164
- }
2165
-
2166
- if ($this->Mailer != 'mail') {
2167
- $result .= $this->LE;
2168
- }
2169
-
2170
- return $result;
2171
- }
2172
-
2173
- /**
2174
- * Returns the whole MIME message.
2175
- * Includes complete headers and body.
2176
- * Only valid post preSend().
2177
- * @see PHPMailer::preSend()
2178
- * @access public
2179
- * @return string
2180
- */
2181
- public function getSentMIMEMessage()
2182
- {
2183
- return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
2184
- }
2185
-
2186
- /**
2187
- * Create unique ID
2188
- * @return string
2189
- */
2190
- protected function generateId() {
2191
- return md5(uniqid(time()));
2192
- }
2193
-
2194
- /**
2195
- * Assemble the message body.
2196
- * Returns an empty string on failure.
2197
- * @access public
2198
- * @throws phpmailerException
2199
- * @return string The assembled message body
2200
- */
2201
- public function createBody()
2202
- {
2203
- $body = '';
2204
- //Create unique IDs and preset boundaries
2205
- $this->uniqueid = $this->generateId();
2206
- $this->boundary[1] = 'b1_' . $this->uniqueid;
2207
- $this->boundary[2] = 'b2_' . $this->uniqueid;
2208
- $this->boundary[3] = 'b3_' . $this->uniqueid;
2209
-
2210
- if ($this->sign_key_file) {
2211
- $body .= $this->getMailMIME() . $this->LE;
2212
- }
2213
-
2214
- $this->setWordWrap();
2215
-
2216
- $bodyEncoding = $this->Encoding;
2217
- $bodyCharSet = $this->CharSet;
2218
- //Can we do a 7-bit downgrade?
2219
- if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
2220
- $bodyEncoding = '7bit';
2221
- //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
2222
- $bodyCharSet = 'us-ascii';
2223
- }
2224
- //If lines are too long, and we're not already using an encoding that will shorten them,
2225
- //change to quoted-printable transfer encoding for the body part only
2226
- if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
2227
- $bodyEncoding = 'quoted-printable';
2228
- }
2229
-
2230
- $altBodyEncoding = $this->Encoding;
2231
- $altBodyCharSet = $this->CharSet;
2232
- //Can we do a 7-bit downgrade?
2233
- if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
2234
- $altBodyEncoding = '7bit';
2235
- //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
2236
- $altBodyCharSet = 'us-ascii';
2237
- }
2238
- //If lines are too long, and we're not already using an encoding that will shorten them,
2239
- //change to quoted-printable transfer encoding for the alt body part only
2240
- if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
2241
- $altBodyEncoding = 'quoted-printable';
2242
- }
2243
- //Use this as a preamble in all multipart message types
2244
- $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
2245
- switch ($this->message_type) {
2246
- case 'inline':
2247
- $body .= $mimepre;
2248
- $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2249
- $body .= $this->encodeString($this->Body, $bodyEncoding);
2250
- $body .= $this->LE . $this->LE;
2251
- $body .= $this->attachAll('inline', $this->boundary[1]);
2252
- break;
2253
- case 'attach':
2254
- $body .= $mimepre;
2255
- $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2256
- $body .= $this->encodeString($this->Body, $bodyEncoding);
2257
- $body .= $this->LE . $this->LE;
2258
- $body .= $this->attachAll('attachment', $this->boundary[1]);
2259
- break;
2260
- case 'inline_attach':
2261
- $body .= $mimepre;
2262
- $body .= $this->textLine('--' . $this->boundary[1]);
2263
- $body .= $this->headerLine('Content-Type', 'multipart/related;');
2264
- $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2265
- $body .= $this->LE;
2266
- $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
2267
- $body .= $this->encodeString($this->Body, $bodyEncoding);
2268
- $body .= $this->LE . $this->LE;
2269
- $body .= $this->attachAll('inline', $this->boundary[2]);
2270
- $body .= $this->LE;
2271
- $body .= $this->attachAll('attachment', $this->boundary[1]);
2272
- break;
2273
- case 'alt':
2274
- $body .= $mimepre;
2275
- $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2276
- $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2277
- $body .= $this->LE . $this->LE;
2278
- $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
2279
- $body .= $this->encodeString($this->Body, $bodyEncoding);
2280
- $body .= $this->LE . $this->LE;
2281
- if (!empty($this->Ical)) {
2282
- $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
2283
- $body .= $this->encodeString($this->Ical, $this->Encoding);
2284
- $body .= $this->LE . $this->LE;
2285
- }
2286
- $body .= $this->endBoundary($this->boundary[1]);
2287
- break;
2288
- case 'alt_inline':
2289
- $body .= $mimepre;
2290
- $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2291
- $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2292
- $body .= $this->LE . $this->LE;
2293
- $body .= $this->textLine('--' . $this->boundary[1]);
2294
- $body .= $this->headerLine('Content-Type', 'multipart/related;');
2295
- $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2296
- $body .= $this->LE;
2297
- $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2298
- $body .= $this->encodeString($this->Body, $bodyEncoding);
2299
- $body .= $this->LE . $this->LE;
2300
- $body .= $this->attachAll('inline', $this->boundary[2]);
2301
- $body .= $this->LE;
2302
- $body .= $this->endBoundary($this->boundary[1]);
2303
- break;
2304
- case 'alt_attach':
2305
- $body .= $mimepre;
2306
- $body .= $this->textLine('--' . $this->boundary[1]);
2307
- $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2308
- $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2309
- $body .= $this->LE;
2310
- $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2311
- $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2312
- $body .= $this->LE . $this->LE;
2313
- $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2314
- $body .= $this->encodeString($this->Body, $bodyEncoding);
2315
- $body .= $this->LE . $this->LE;
2316
- $body .= $this->endBoundary($this->boundary[2]);
2317
- $body .= $this->LE;
2318
- $body .= $this->attachAll('attachment', $this->boundary[1]);
2319
- break;
2320
- case 'alt_inline_attach':
2321
- $body .= $mimepre;
2322
- $body .= $this->textLine('--' . $this->boundary[1]);
2323
- $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2324
- $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2325
- $body .= $this->LE;
2326
- $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2327
- $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2328
- $body .= $this->LE . $this->LE;
2329
- $body .= $this->textLine('--' . $this->boundary[2]);
2330
- $body .= $this->headerLine('Content-Type', 'multipart/related;');
2331
- $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
2332
- $body .= $this->LE;
2333
- $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2334
- $body .= $this->encodeString($this->Body, $bodyEncoding);
2335
- $body .= $this->LE . $this->LE;
2336
- $body .= $this->attachAll('inline', $this->boundary[3]);
2337
- $body .= $this->LE;
2338
- $body .= $this->endBoundary($this->boundary[2]);
2339
- $body .= $this->LE;
2340
- $body .= $this->attachAll('attachment', $this->boundary[1]);
2341
- break;
2342
- default:
2343
- // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
2344
- //Reset the `Encoding` property in case we changed it for line length reasons
2345
- $this->Encoding = $bodyEncoding;
2346
- $body .= $this->encodeString($this->Body, $this->Encoding);
2347
- break;
2348
- }
2349
-
2350
- if ($this->isError()) {
2351
- $body = '';
2352
- } elseif ($this->sign_key_file) {
2353
- try {
2354
- if (!defined('PKCS7_TEXT')) {
2355
- throw new phpmailerException($this->lang('extension_missing') . 'openssl');
2356
- }
2357
- // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
2358
- $file = tempnam(sys_get_temp_dir(), 'mail');
2359
- if (false === file_put_contents($file, $body)) {
2360
- throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
2361
- }
2362
- $signed = tempnam(sys_get_temp_dir(), 'signed');
2363
- //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
2364
- if (empty($this->sign_extracerts_file)) {
2365
- $sign = @openssl_pkcs7_sign(
2366
- $file,
2367
- $signed,
2368
- 'file://' . realpath($this->sign_cert_file),
2369
- array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2370
- null
2371
- );
2372
- } else {
2373
- $sign = @openssl_pkcs7_sign(
2374
- $file,
2375
- $signed,
2376
- 'file://' . realpath($this->sign_cert_file),
2377
- array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2378
- null,
2379
- PKCS7_DETACHED,
2380
- $this->sign_extracerts_file
2381
- );
2382
- }
2383
- if ($sign) {
2384
- @unlink($file);
2385
- $body = file_get_contents($signed);
2386
- @unlink($signed);
2387
- //The message returned by openssl contains both headers and body, so need to split them up
2388
- $parts = explode("\n\n", $body, 2);
2389
- $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
2390
- $body = $parts[1];
2391
- } else {
2392
- @unlink($file);
2393
- @unlink($signed);
2394
- throw new phpmailerException($this->lang('signing') . openssl_error_string());
2395
- }
2396
- } catch (phpmailerException $exc) {
2397
- $body = '';
2398
- if ($this->exceptions) {
2399
- throw $exc;
2400
- }
2401
- }
2402
- }
2403
- return $body;
2404
- }
2405
-
2406
- /**
2407
- * Return the start of a message boundary.
2408
- * @access protected
2409
- * @param string $boundary
2410
- * @param string $charSet
2411
- * @param string $contentType
2412
- * @param string $encoding
2413
- * @return string
2414
- */
2415
- protected function getBoundary($boundary, $charSet, $contentType, $encoding)
2416
- {
2417
- $result = '';
2418
- if ($charSet == '') {
2419
- $charSet = $this->CharSet;
2420
- }
2421
- if ($contentType == '') {
2422
- $contentType = $this->ContentType;
2423
- }
2424
- if ($encoding == '') {
2425
- $encoding = $this->Encoding;
2426
- }
2427
- $result .= $this->textLine('--' . $boundary);
2428
- $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
2429
- $result .= $this->LE;
2430
- // RFC1341 part 5 says 7bit is assumed if not specified
2431
- if ($encoding != '7bit') {
2432
- $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
2433
- }
2434
- $result .= $this->LE;
2435
-
2436
- return $result;
2437
- }
2438
-
2439
- /**
2440
- * Return the end of a message boundary.
2441
- * @access protected
2442
- * @param string $boundary
2443
- * @return string
2444
- */
2445
- protected function endBoundary($boundary)
2446
- {
2447
- return $this->LE . '--' . $boundary . '--' . $this->LE;
2448
- }
2449
-
2450
- /**
2451
- * Set the message type.
2452
- * PHPMailer only supports some preset message types, not arbitrary MIME structures.
2453
- * @access protected
2454
- * @return void
2455
- */
2456
- protected function setMessageType()
2457
- {
2458
- $type = array();
2459
- if ($this->alternativeExists()) {
2460
- $type[] = 'alt';
2461
- }
2462
- if ($this->inlineImageExists()) {
2463
- $type[] = 'inline';
2464
- }
2465
- if ($this->attachmentExists()) {
2466
- $type[] = 'attach';
2467
- }
2468
- $this->message_type = implode('_', $type);
2469
- if ($this->message_type == '') {
2470
- //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
2471
- $this->message_type = 'plain';
2472
- }
2473
- }
2474
-
2475
- /**
2476
- * Format a header line.
2477
- * @access public
2478
- * @param string $name
2479
- * @param string $value
2480
- * @return string
2481
- */
2482
- public function headerLine($name, $value)
2483
- {
2484
- return $name . ': ' . $value . $this->LE;
2485
- }
2486
-
2487
- /**
2488
- * Return a formatted mail line.
2489
- * @access public
2490
- * @param string $value
2491
- * @return string
2492
- */
2493
- public function textLine($value)
2494
- {
2495
- return $value . $this->LE;
2496
- }
2497
-
2498
- /**
2499
- * Add an attachment from a path on the filesystem.
2500
- * Never use a user-supplied path to a file!
2501
- * Returns false if the file could not be found or read.
2502
- * @param string $path Path to the attachment.
2503
- * @param string $name Overrides the attachment name.
2504
- * @param string $encoding File encoding (see $Encoding).
2505
- * @param string $type File extension (MIME) type.
2506
- * @param string $disposition Disposition to use
2507
- * @throws phpmailerException
2508
- * @return boolean
2509
- */
2510
- public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2511
- {
2512
- try {
2513
- if (!@is_file($path)) {
2514
- throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2515
- }
2516
-
2517
- // If a MIME type is not specified, try to work it out from the file name
2518
- if ($type == '') {
2519
- $type = self::filenameToType($path);
2520
- }
2521
-
2522
- $filename = basename($path);
2523
- if ($name == '') {
2524
- $name = $filename;
2525
- }
2526
-
2527
- $this->attachment[] = array(
2528
- 0 => $path,
2529
- 1 => $filename,
2530
- 2 => $name,
2531
- 3 => $encoding,
2532
- 4 => $type,
2533
- 5 => false, // isStringAttachment
2534
- 6 => $disposition,
2535
- 7 => 0
2536
- );
2537
-
2538
- } catch (phpmailerException $exc) {
2539
- $this->setError($exc->getMessage());
2540
- $this->edebug($exc->getMessage());
2541
- if ($this->exceptions) {
2542
- throw $exc;
2543
- }
2544
- return false;
2545
- }
2546
- return true;
2547
- }
2548
-
2549
- /**
2550
- * Return the array of attachments.
2551
- * @return array
2552
- */
2553
- public function getAttachments()
2554
- {
2555
- return $this->attachment;
2556
- }
2557
-
2558
- /**
2559
- * Attach all file, string, and binary attachments to the message.
2560
- * Returns an empty string on failure.
2561
- * @access protected
2562
- * @param string $disposition_type
2563
- * @param string $boundary
2564
- * @return string
2565
- */
2566
- protected function attachAll($disposition_type, $boundary)
2567
- {
2568
- // Return text of body
2569
- $mime = array();
2570
- $cidUniq = array();
2571
- $incl = array();
2572
-
2573
- // Add all attachments
2574
- foreach ($this->attachment as $attachment) {
2575
- // Check if it is a valid disposition_filter
2576
- if ($attachment[6] == $disposition_type) {
2577
- // Check for string attachment
2578
- $string = '';
2579
- $path = '';
2580
- $bString = $attachment[5];
2581
- if ($bString) {
2582
- $string = $attachment[0];
2583
- } else {
2584
- $path = $attachment[0];
2585
- }
2586
-
2587
- $inclhash = md5(serialize($attachment));
2588
- if (in_array($inclhash, $incl)) {
2589
- continue;
2590
- }
2591
- $incl[] = $inclhash;
2592
- $name = $attachment[2];
2593
- $encoding = $attachment[3];
2594
- $type = $attachment[4];
2595
- $disposition = $attachment[6];
2596
- $cid = $attachment[7];
2597
- if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
2598
- continue;
2599
- }
2600
- $cidUniq[$cid] = true;
2601
-
2602
- $mime[] = sprintf('--%s%s', $boundary, $this->LE);
2603
- //Only include a filename property if we have one
2604
- if (!empty($name)) {
2605
- $mime[] = sprintf(
2606
- 'Content-Type: %s; name="%s"%s',
2607
- $type,
2608
- $this->encodeHeader($this->secureHeader($name)),
2609
- $this->LE
2610
- );
2611
- } else {
2612
- $mime[] = sprintf(
2613
- 'Content-Type: %s%s',
2614
- $type,
2615
- $this->LE
2616
- );
2617
- }
2618
- // RFC1341 part 5 says 7bit is assumed if not specified
2619
- if ($encoding != '7bit') {
2620
- $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2621
- }
2622
-
2623
- if ($disposition == 'inline') {
2624
- $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
2625
- }
2626
-
2627
- // If a filename contains any of these chars, it should be quoted,
2628
- // but not otherwise: RFC2183 & RFC2045 5.1
2629
- // Fixes a warning in IETF's msglint MIME checker
2630
- // Allow for bypassing the Content-Disposition header totally
2631
- if (!(empty($disposition))) {
2632
- $encoded_name = $this->encodeHeader($this->secureHeader($name));
2633
- if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
2634
- $mime[] = sprintf(
2635
- 'Content-Disposition: %s; filename="%s"%s',
2636
- $disposition,
2637
- $encoded_name,
2638
- $this->LE . $this->LE
2639
- );
2640
- } else {
2641
- if (!empty($encoded_name)) {
2642
- $mime[] = sprintf(
2643
- 'Content-Disposition: %s; filename=%s%s',
2644
- $disposition,
2645
- $encoded_name,
2646
- $this->LE . $this->LE
2647
- );
2648
- } else {
2649
- $mime[] = sprintf(
2650
- 'Content-Disposition: %s%s',
2651
- $disposition,
2652
- $this->LE . $this->LE
2653
- );
2654
- }
2655
- }
2656
- } else {
2657
- $mime[] = $this->LE;
2658
- }
2659
-
2660
- // Encode as string attachment
2661
- if ($bString) {
2662
- $mime[] = $this->encodeString($string, $encoding);
2663
- if ($this->isError()) {
2664
- return '';
2665
- }
2666
- $mime[] = $this->LE . $this->LE;
2667
- } else {
2668
- $mime[] = $this->encodeFile($path, $encoding);
2669
- if ($this->isError()) {
2670
- return '';
2671
- }
2672
- $mime[] = $this->LE . $this->LE;
2673
- }
2674
- }
2675
- }
2676
-
2677
- $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
2678
-
2679
- return implode('', $mime);
2680
- }
2681
-
2682
- /**
2683
- * Encode a file attachment in requested format.
2684
- * Returns an empty string on failure.
2685
- * @param string $path The full path to the file
2686
- * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2687
- * @throws phpmailerException
2688
- * @access protected
2689
- * @return string
2690
- */
2691
- protected function encodeFile($path, $encoding = 'base64')
2692
- {
2693
- try {
2694
- if (!is_readable($path)) {
2695
- throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2696
- }
2697
- $magic_quotes = get_magic_quotes_runtime();
2698
- if ($magic_quotes) {
2699
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2700
- set_magic_quotes_runtime(false);
2701
- } else {
2702
- //Doesn't exist in PHP 5.4, but we don't need to check because
2703
- //get_magic_quotes_runtime always returns false in 5.4+
2704
- //so it will never get here
2705
- ini_set('magic_quotes_runtime', false);
2706
- }
2707
- }
2708
- $file_buffer = file_get_contents($path);
2709
- $file_buffer = $this->encodeString($file_buffer, $encoding);
2710
- if ($magic_quotes) {
2711
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2712
- set_magic_quotes_runtime($magic_quotes);
2713
- } else {
2714
- ini_set('magic_quotes_runtime', $magic_quotes);
2715
- }
2716
- }
2717
- return $file_buffer;
2718
- } catch (Exception $exc) {
2719
- $this->setError($exc->getMessage());
2720
- return '';
2721
- }
2722
- }
2723
-
2724
- /**
2725
- * Encode a string in requested format.
2726
- * Returns an empty string on failure.
2727
- * @param string $str The text to encode
2728
- * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2729
- * @access public
2730
- * @return string
2731
- */
2732
- public function encodeString($str, $encoding = 'base64')
2733
- {
2734
- $encoded = '';
2735
- switch (strtolower($encoding)) {
2736
- case 'base64':
2737
- $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2738
- break;
2739
- case '7bit':
2740
- case '8bit':
2741
- $encoded = $this->fixEOL($str);
2742
- // Make sure it ends with a line break
2743
- if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2744
- $encoded .= $this->LE;
2745
- }
2746
- break;
2747
- case 'binary':
2748
- $encoded = $str;
2749
- break;
2750
- case 'quoted-printable':
2751
- $encoded = $this->encodeQP($str);
2752
- break;
2753
- default:
2754
- $this->setError($this->lang('encoding') . $encoding);
2755
- break;
2756
- }
2757
- return $encoded;
2758
- }
2759
-
2760
- /**
2761
- * Encode a header string optimally.
2762
- * Picks shortest of Q, B, quoted-printable or none.
2763
- * @access public
2764
- * @param string $str
2765
- * @param string $position
2766
- * @return string
2767
- */
2768
- public function encodeHeader($str, $position = 'text')
2769
- {
2770
- $matchcount = 0;
2771
- switch (strtolower($position)) {
2772
- case 'phrase':
2773
- if (!preg_match('/[\200-\377]/', $str)) {
2774
- // Can't use addslashes as we don't know the value of magic_quotes_sybase
2775
- $encoded = addcslashes($str, "\0..\37\177\\\"");
2776
- if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2777
- return ($encoded);
2778
- } else {
2779
- return ("\"$encoded\"");
2780
- }
2781
- }
2782
- $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
2783
- break;
2784
- /** @noinspection PhpMissingBreakStatementInspection */
2785
- case 'comment':
2786
- $matchcount = preg_match_all('/[()"]/', $str, $matches);
2787
- // Intentional fall-through
2788
- case 'text':
2789
- default:
2790
- $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
2791
- break;
2792
- }
2793
-
2794
- //There are no chars that need encoding
2795
- if ($matchcount == 0) {
2796
- return ($str);
2797
- }
2798
-
2799
- $maxlen = 75 - 7 - strlen($this->CharSet);
2800
- // Try to select the encoding which should produce the shortest output
2801
- if ($matchcount > strlen($str) / 3) {
2802
- // More than a third of the content will need encoding, so B encoding will be most efficient
2803
- $encoding = 'B';
2804
- if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2805
- // Use a custom function which correctly encodes and wraps long
2806
- // multibyte strings without breaking lines within a character
2807
- $encoded = $this->base64EncodeWrapMB($str, "\n");
2808
- } else {
2809
- $encoded = base64_encode($str);
2810
- $maxlen -= $maxlen % 4;
2811
- $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2812
- }
2813
- } else {
2814
- $encoding = 'Q';
2815
- $encoded = $this->encodeQ($str, $position);
2816
- $encoded = $this->wrapText($encoded, $maxlen, true);
2817
- $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2818
- }
2819
-
2820
- $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
2821
- $encoded = trim(str_replace("\n", $this->LE, $encoded));
2822
-
2823
- return $encoded;
2824
- }
2825
-
2826
- /**
2827
- * Check if a string contains multi-byte characters.
2828
- * @access public
2829
- * @param string $str multi-byte text to wrap encode
2830
- * @return boolean
2831
- */
2832
- public function hasMultiBytes($str)
2833
- {
2834
- if (function_exists('mb_strlen')) {
2835
- return (strlen($str) > mb_strlen($str, $this->CharSet));
2836
- } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
2837
- return false;
2838
- }
2839
- }
2840
-
2841
- /**
2842
- * Does a string contain any 8-bit chars (in any charset)?
2843
- * @param string $text
2844
- * @return boolean
2845
- */
2846
- public function has8bitChars($text)
2847
- {
2848
- return (boolean)preg_match('/[\x80-\xFF]/', $text);
2849
- }
2850
-
2851
- /**
2852
- * Encode and wrap long multibyte strings for mail headers
2853
- * without breaking lines within a character.
2854
- * Adapted from a function by paravoid
2855
- * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
2856
- * @access public
2857
- * @param string $str multi-byte text to wrap encode
2858
- * @param string $linebreak string to use as linefeed/end-of-line
2859
- * @return string
2860
- */
2861
- public function base64EncodeWrapMB($str, $linebreak = null)
2862
- {
2863
- $start = '=?' . $this->CharSet . '?B?';
2864
- $end = '?=';
2865
- $encoded = '';
2866
- if ($linebreak === null) {
2867
- $linebreak = $this->LE;
2868
- }
2869
-
2870
- $mb_length = mb_strlen($str, $this->CharSet);
2871
- // Each line must have length <= 75, including $start and $end
2872
- $length = 75 - strlen($start) - strlen($end);
2873
- // Average multi-byte ratio
2874
- $ratio = $mb_length / strlen($str);
2875
- // Base64 has a 4:3 ratio
2876
- $avgLength = floor($length * $ratio * .75);
2877
-
2878
- for ($i = 0; $i < $mb_length; $i += $offset) {
2879
- $lookBack = 0;
2880
- do {
2881
- $offset = $avgLength - $lookBack;
2882
- $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2883
- $chunk = base64_encode($chunk);
2884
- $lookBack++;
2885
- } while (strlen($chunk) > $length);
2886
- $encoded .= $chunk . $linebreak;
2887
- }
2888
-
2889