PageRenderTime 40ms CodeModel.GetById 5ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 1ms

/wacko/lib/phpmailer/class.phpmailer.php

https://bitbucket.org/wackowiki/wackowiki-dev
PHP | 4039 lines | 2374 code | 251 blank | 1414 comment | 391 complexity | bbedafbc452cb88b9aee343a1f53c871 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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 */
  28class PHPMailer
  29{
  30    /**
  31     * The PHPMailer Version number.
  32     * @var string
  33     */
  34    public $Version = '5.2.23';
  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     *   string  $to            email address of the recipient
 444     *   string  $cc            cc email addresses
 445     *   string  $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    }
 663
 664    /**
 665     * Destructor.
 666     */
 667    public function __destruct()
 668    {
 669        //Close any open SMTP connection nicely
 670        $this->smtpClose();
 671    }
 672
 673    /**
 674     * Call mail() in a safe_mode-aware fashion.
 675     * Also, unless sendmail_path points to sendmail (or something that
 676     * claims to be sendmail), don't pass params (not a perfect fix,
 677     * but it will do)
 678     * @param string $to To
 679     * @param string $subject Subject
 680     * @param string $body Message Body
 681     * @param string $header Additional Header(s)
 682     * @param string $params Params
 683     * @access private
 684     * @return boolean
 685     */
 686    private function mailPassthru($to, $subject, $body, $header, $params)
 687    {
 688        //Check overloading of mail function to avoid double-encoding
 689        if (ini_get('mbstring.func_overload') & 1) {
 690            $subject = $this->secureHeader($subject);
 691        } else {
 692            $subject = $this->encodeHeader($this->secureHeader($subject));
 693        }
 694
 695        //Can't use additional_parameters in safe_mode, calling mail() with null params breaks
 696        //@link http://php.net/manual/en/function.mail.php
 697        if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
 698            $result = @mail($to, $subject, $body, $header);
 699        } else {
 700            $result = @mail($to, $subject, $body, $header, $params);
 701        }
 702        return $result;
 703    }
 704    /**
 705     * Output debugging info via user-defined method.
 706     * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
 707     * @see PHPMailer::$Debugoutput
 708     * @see PHPMailer::$SMTPDebug
 709     * @param string $str
 710     */
 711    protected function edebug($str)
 712    {
 713        if ($this->SMTPDebug <= 0) {
 714            return;
 715        }
 716        //Avoid clash with built-in function names
 717        if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
 718            call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
 719            return;
 720        }
 721        switch ($this->Debugoutput) {
 722            case 'error_log':
 723                //Don't output, just log
 724                error_log($str);
 725                break;
 726            case 'html':
 727                //Cleans up output a bit for a better looking, HTML-safe output
 728                echo htmlentities(
 729                    preg_replace('/[\r\n]+/', '', $str),
 730                    ENT_QUOTES,
 731                    'UTF-8'
 732                )
 733                . "<br>\n";
 734                break;
 735            case 'echo':
 736            default:
 737                //Normalize line breaks
 738                $str = preg_replace('/\r\n?/ms', "\n", $str);
 739                echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
 740                    "\n",
 741                    "\n                   \t                  ",
 742                    trim($str)
 743                ) . "\n";
 744        }
 745    }
 746
 747    /**
 748     * Sets message type to HTML or plain.
 749     * @param boolean $isHtml True for HTML mode.
 750     * @return void
 751     */
 752    public function isHTML($isHtml = true)
 753    {
 754        if ($isHtml) {
 755            $this->ContentType = 'text/html';
 756        } else {
 757            $this->ContentType = 'text/plain';
 758        }
 759    }
 760
 761    /**
 762     * Send messages using SMTP.
 763     * @return void
 764     */
 765    public function isSMTP()
 766    {
 767        $this->Mailer = 'smtp';
 768    }
 769
 770    /**
 771     * Send messages using PHP's mail() function.
 772     * @return void
 773     */
 774    public function isMail()
 775    {
 776        $this->Mailer = 'mail';
 777    }
 778
 779    /**
 780     * Send messages using $Sendmail.
 781     * @return void
 782     */
 783    public function isSendmail()
 784    {
 785        $ini_sendmail_path = ini_get('sendmail_path');
 786
 787        if (!stristr($ini_sendmail_path, 'sendmail')) {
 788            $this->Sendmail = '/usr/sbin/sendmail';
 789        } else {
 790            $this->Sendmail = $ini_sendmail_path;
 791        }
 792        $this->Mailer = 'sendmail';
 793    }
 794
 795    /**
 796     * Send messages using qmail.
 797     * @return void
 798     */
 799    public function isQmail()
 800    {
 801        $ini_sendmail_path = ini_get('sendmail_path');
 802
 803        if (!stristr($ini_sendmail_path, 'qmail')) {
 804            $this->Sendmail = '/var/qmail/bin/qmail-inject';
 805        } else {
 806            $this->Sendmail = $ini_sendmail_path;
 807        }
 808        $this->Mailer = 'qmail';
 809    }
 810
 811    /**
 812     * Add a "To" address.
 813     * @param string $address The email address to send to
 814     * @param string $name
 815     * @return boolean true on success, false if address already used or invalid in some way
 816     */
 817    public function addAddress($address, $name = '')
 818    {
 819        return $this->addOrEnqueueAnAddress('to', $address, $name);
 820    }
 821
 822    /**
 823     * Add a "CC" address.
 824     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
 825     * @param string $address The email address to send to
 826     * @param string $name
 827     * @return boolean true on success, false if address already used or invalid in some way
 828     */
 829    public function addCC($address, $name = '')
 830    {
 831        return $this->addOrEnqueueAnAddress('cc', $address, $name);
 832    }
 833
 834    /**
 835     * Add a "BCC" address.
 836     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
 837     * @param string $address The email address to send to
 838     * @param string $name
 839     * @return boolean true on success, false if address already used or invalid in some way
 840     */
 841    public function addBCC($address, $name = '')
 842    {
 843        return $this->addOrEnqueueAnAddress('bcc', $address, $name);
 844    }
 845
 846    /**
 847     * Add a "Reply-To" address.
 848     * @param string $address The email address to reply to
 849     * @param string $name
 850     * @return boolean true on success, false if address already used or invalid in some way
 851     */
 852    public function addReplyTo($address, $name = '')
 853    {
 854        return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
 855    }
 856
 857    /**
 858     * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
 859     * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
 860     * be modified after calling this function), addition of such addresses is delayed until send().
 861     * Addresses that have been added already return false, but do not throw exceptions.
 862     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
 863     * @param string $address The email address to send, resp. to reply to
 864     * @param string $name
 865     * @throws phpmailerException
 866     * @return boolean true on success, false if address already used or invalid in some way
 867     * @access protected
 868     */
 869    protected function addOrEnqueueAnAddress($kind, $address, $name)
 870    {
 871        $address = trim($address);
 872        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
 873        if (($pos = strrpos($address, '@')) === false) {
 874            // At-sign is misssing.
 875            $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
 876            $this->setError($error_message);
 877            $this->edebug($error_message);
 878            if ($this->exceptions) {
 879                throw new phpmailerException($error_message);
 880            }
 881            return false;
 882        }
 883        $params = array($kind, $address, $name);
 884        // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
 885        if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
 886            if ($kind != 'Reply-To') {
 887                if (!array_key_exists($address, $this->RecipientsQueue)) {
 888                    $this->RecipientsQueue[$address] = $params;
 889                    return true;
 890                }
 891            } else {
 892                if (!array_key_exists($address, $this->ReplyToQueue)) {
 893                    $this->ReplyToQueue[$address] = $params;
 894                    return true;
 895                }
 896            }
 897            return false;
 898        }
 899        // Immediately add standard addresses without IDN.
 900        return call_user_func_array(array($this, 'addAnAddress'), $params);
 901    }
 902
 903    /**
 904     * Add an address to one of the recipient arrays or to the ReplyTo array.
 905     * Addresses that have been added already return false, but do not throw exceptions.
 906     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
 907     * @param string $address The email address to send, resp. to reply to
 908     * @param string $name
 909     * @throws phpmailerException
 910     * @return boolean true on success, false if address already used or invalid in some way
 911     * @access protected
 912     */
 913    protected function addAnAddress($kind, $address, $name = '')
 914    {
 915        if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
 916            $error_message = $this->lang('Invalid recipient kind: ') . $kind;
 917            $this->setError($error_message);
 918            $this->edebug($error_message);
 919            if ($this->exceptions) {
 920                throw new phpmailerException($error_message);
 921            }
 922            return false;
 923        }
 924        if (!$this->validateAddress($address)) {
 925            $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
 926            $this->setError($error_message);
 927            $this->edebug($error_message);
 928            if ($this->exceptions) {
 929                throw new phpmailerException($error_message);
 930            }
 931            return false;
 932        }
 933        if ($kind != 'Reply-To') {
 934            if (!array_key_exists(strtolower($address), $this->all_recipients)) {
 935                array_push($this->$kind, array($address, $name));
 936                $this->all_recipients[strtolower($address)] = true;
 937                return true;
 938            }
 939        } else {
 940            if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
 941                $this->ReplyTo[strtolower($address)] = array($address, $name);
 942                return true;
 943            }
 944        }
 945        return false;
 946    }
 947
 948    /**
 949     * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
 950     * of the form "display name <address>" into an array of name/address pairs.
 951     * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
 952     * Note that quotes in the name part are removed.
 953     * @param string $addrstr The address list string
 954     * @param bool $useimap Whether to use the IMAP extension to parse the list
 955     * @return array
 956     * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
 957     */
 958    public function parseAddresses($addrstr, $useimap = true)
 959    {
 960        $addresses = array();
 961        if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
 962            //Use this built-in parser if it's available
 963            $list = imap_rfc822_parse_adrlist($addrstr, '');
 964            foreach ($list as $address) {
 965                if ($address->host != '.SYNTAX-ERROR.') {
 966                    if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
 967                        $addresses[] = array(
 968                            'name' => (property_exists($address, 'personal') ? $address->personal : ''),
 969                            'address' => $address->mailbox . '@' . $address->host
 970                        );
 971                    }
 972                }
 973            }
 974        } else {
 975            //Use this simpler parser
 976            $list = explode(',', $addrstr);
 977            foreach ($list as $address) {
 978                $address = trim($address);
 979                //Is there a separate name part?
 980                if (strpos($address, '<') === false) {
 981                    //No separate name, just use the whole thing
 982                    if ($this->validateAddress($address)) {
 983                        $addresses[] = array(
 984                            'name' => '',
 985                            'address' => $address
 986                        );
 987                    }
 988                } else {
 989                    list($name, $email) = explode('<', $address);
 990                    $email = trim(str_replace('>', '', $email));
 991                    if ($this->validateAddress($email)) {
 992                        $addresses[] = array(
 993                            'name' => trim(str_replace(array('"', "'"), '', $name)),
 994                            'address' => $email
 995                        );
 996                    }
 997                }
 998            }
 999        }
1000        return $addresses;
1001    }
1002
1003    /**
1004     * Set the From and FromName properties.
1005     * @param string $address
1006     * @param string $name
1007     * @param boolean $auto Whether to also set the Sender address, defaults to true
1008     * @throws phpmailerException
1009     * @return boolean
1010     */
1011    public function setFrom($address, $name = '', $auto = true)
1012    {
1013        $address = trim($address);
1014        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
1015        // Don't validate now addresses with IDN. Will be done in send().
1016        if (($pos = strrpos($address, '@')) === false or
1017            (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
1018            !$this->validateAddress($address)) {
1019            $error_message = $this->lang('invalid_address') . " (setFrom) $address";
1020            $this->setError($error_message);
1021            $this->edebug($error_message);
1022            if ($this->exceptions) {
1023                throw new phpmailerException($error_message);
1024            }
1025            return false;
1026        }
1027        $this->From = $address;
1028        $this->FromName = $name;
1029        if ($auto) {
1030            if (empty($this->Sender)) {
1031                $this->Sender = $address;
1032            }
1033        }
1034        return true;
1035    }
1036
1037    /**
1038     * Return the Message-ID header of the last email.
1039     * Technically this is the value from the last time the headers were created,
1040     * but it's also the message ID of the last sent message except in
1041     * pathological cases.
1042     * @return string
1043     */
1044    public function getLastMessageID()
1045    {
1046        return $this->lastMessageID;
1047    }
1048
1049    /**
1050     * Check that a string looks like an email address.
1051     * @param string $address The email address to check
1052     * @param string|callable $patternselect A selector for the validation pattern to use :
1053     * * `auto` Pick best pattern automatically;
1054     * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
1055     * * `pcre` Use old PCRE implementation;
1056     * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
1057     * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
1058     * * `noregex` Don't use a regex: super fast, really dumb.
1059     * Alternatively you may pass in a callable to inject your own validator, for example:
1060     * PHPMailer::validateAddress('user@example.com', function($address) {
1061     *     return (strpos($address, '@') !== false);
1062     * });
1063     * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
1064     * @return boolean
1065     * @static
1066     * @access public
1067     */
1068    public static function validateAddress($address, $patternselect = null)
1069    {
1070        if (is_null($patternselect)) {
1071            $patternselect = self::$validator;
1072        }
1073        if (is_callable($patternselect)) {
1074            return call_user_func($patternselect, $address);
1075        }
1076        //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
1077        if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
1078            return false;
1079        }
1080        if (!$patternselect or $patternselect == 'auto') {
1081            //Check this constant first so it works when extension_loaded() is disabled by safe mode
1082            //Constant was added in PHP 5.2.4
1083            if (defined('PCRE_VERSION')) {
1084                //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
1085                if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
1086                    $patternselect = 'pcre8';
1087                } else {
1088                    $patternselect = 'pcre';
1089                }
1090            } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
1091                //Fall back to older PCRE
1092                $patternselect = 'pcre';
1093            } else {
1094                //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
1095                if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
1096                    $patternselect = 'php';
1097                } else {
1098                    $patternselect = 'noregex';
1099                }
1100            }
1101        }
1102        switch ($patternselect) {
1103            case 'pcre8':
1104                /**
1105                 * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
1106                 * @link http://squiloople.com/2009/12/20/email-address-validation/
1107                 * @copyright 2009-2010 Michael Rushton
1108                 * Feel free to use and redistribute this code. But please keep this copyright notice.
1109                 */
1110                return (boolean)preg_match(
1111                    '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
1112                    '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
1113                    '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
1114                    '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
1115                    '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
1116                    '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
1117                    '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
1118                    '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1119                    '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
1120                    $address
1121                );
1122            case 'pcre':
1123                //An older regex that doesn't need a recent PCRE
1124                return (boolean)preg_match(
1125                    '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
1126                    '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
1127                    '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
1128                    '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
1129                    '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
1130                    '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
1131                    '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
1132                    '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
1133                    '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1134                    '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
1135                    $address
1136                );
1137            case 'html5':
1138                /**
1139                 * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
1140                 * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
1141                 */
1142                return (boolean)preg_match(
1143                    '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
1144                    '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
1145                    $address
1146                );
1147            case 'noregex':
1148                //No PCRE! Do something _very_ approximate!
1149                //Check the address is 3 chars or longer and contains an @ that's not the first or last char
1150                return (strlen($address) >= 3
1151                    and strpos($address, '@') >= 1
1152                    and strpos($address, '@') != strlen($address) - 1);
1153            case 'php':
1154            default:
1155                return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
1156        }
1157    }
1158
1159    /**
1160     * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
1161     * "intl" and "mbstring" PHP extensions.
1162     * @return bool "true" if required functions for IDN support are present
1163     */
1164    public function idnSupported()
1165    {
1166        // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
1167        return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
1168    }
1169
1170    /**
1171     * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
1172     * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
1173     * This function silently returns unmodified address if:
1174     * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
1175     * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
1176     *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
1177     * @see PHPMailer::$CharSet
1178     * @param string $address The email address to convert
1179     * @return string The encoded address in ASCII form
1180     */
1181    public function punyencodeAddress($address)
1182    {
1183        // Verify we have required functions, CharSet, and at-sign.
1184        if ($this->idnSupported() and
1185            !empty($this->CharSet) and
1186            ($pos = strrpos($address, '@')) !== false) {
1187            $domain = substr($address, ++$pos);
1188            // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
1189            if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
1190                $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
1191                if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
1192                    idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
1193                    idn_to_ascii($domain)) !== false) {
1194                    return substr($address, 0, $pos) . $punycode;
1195                }
1196            }
1197        }
1198        return $address;
1199    }
1200
1201    /**
1202     * Create a message and send it.
1203     * Uses the sending method specified by $Mailer.
1204     * @throws phpmailerException
1205     * @return boolean false on error - See the ErrorInfo property for details of the error.
1206     */
1207    public function send()
1208    {
1209        try {
1210            if (!$this->preSend()) {
1211                return false;
1212            }
1213            return $this->postSend();
1214        } catch (phpmailerException $exc) {
1215            $this->mailHeader = '';
1216            $this->setError($exc->getMessage());
1217            if ($this->exceptions) {
1218                throw $exc;
1219            }
1220            return false;
1221        }
1222    }
1223
1224    /**
1225     * Prepare a message for sending.
1226     * @throws phpmailerException
1227     * @return boolean
1228     */
1229    public function preSend()
1230    {
1231        try {
1232            $this->error_count = 0; // Reset errors
1233            $this->mailHeader = '';
1234
1235            // Dequeue recipient and Reply-To addresses with IDN
1236            foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
1237                $params[1] = $this->punyencodeAddress($params[1]);
1238                call_user_func_array(array($this, 'addAnAddress'), $params);
1239            }
1240            if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
1241                throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
1242            }
1243
1244            // Validate From, Sender, and ConfirmReadingTo addresses
1245            foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
1246                $this->$address_kind = trim($this->$address_kind);
1247                if (empty($this->$address_kind)) {
1248                    continue;
1249                }
1250                $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
1251                if (!$this->validateAddress($this->$address_kind)) {
1252                    $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
1253                    $this->setError($error_message);
1254                    $this->edebug($error_message);
1255                    if ($this->exceptions) {
1256                        throw new phpmailerException($error_message);
1257                    }
1258                    return false;
1259                }
1260            }
1261
1262            // Set whether the message is multipart/alternative
1263            if ($this->alternativeExists()) {
1264                $this->ContentType = 'multipart/alternative';
1265            }
1266
1267            $this->setMessageType();
1268            // Refuse to send an empty message unless we are specifically allowing it
1269            if (!$this->AllowEmpty and empty($this->Body)) {
1270                throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
1271            }
1272
1273            // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
1274            $this->MIMEHeader = '';
1275            $this->MIMEBody = $this->createBody();
1276            // createBody may have added some headers, so retain them
1277            $tempheaders = $this->MIMEHeader;
1278            $this->MIMEHeader = $this->createHeader();
1279            $this->MIMEHeader .= $tempheaders;
1280
1281            // To capture the complete message when using mail(), create
1282            // an extra header list which createHeader() doesn't fold in
1283            if ($this->Mailer == 'mail') {
1284                if (count($this->to) > 0) {
1285                    $this->mailHeader .= $this->addrAppend('To', $this->to);
1286                } else {
1287                    $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
1288                }
1289                $this->mailHeader .= $this->headerLine(
1290                    'Subject',
1291                    $this->encodeHeader($this->secureHeader(trim($this->Subject)))
1292                );
1293            }
1294
1295            // Sign with DKIM if enabled
1296            if (!empty($this->DKIM_domain)
1297                && !empty($this->DKIM_selector)
1298                && (!empty($this->DKIM_private_string)
1299                   || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
1300                )
1301            ) {
1302                $header_dkim = $this->DKIM_Add(
1303                    $this->MIMEHeader . $this->mailHeader,
1304                    $this->encodeHeader($this->secureHeader($this->Subject)),
1305                    $this->MIMEBody
1306                );
1307                $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
1308                    str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
1309            }
1310            return true;
1311        } catch (phpmailerException $exc) {
1312            $this->setError($exc->getMessage());
1313            if ($this->exceptions) {
1314                throw $exc;
1315            }
1316            return false;
1317        }
1318    }
1319
1320    /**
1321     * Actually send a message.
1322     * Send the email via the selected mechanism
1323     * @throws phpmailerException
1324     * @return boolean
1325     */
1326    public function postSend()
1327    {
1328        try {
1329            // Choose the mailer and send through it
1330            switch ($this->Mailer) {
1331                case 'sendmail':
1332                case 'qmail':
1333                    return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
1334                case 'smtp':
1335                    return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
1336                case 'mail':
1337                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1338                default:
1339                    $sendMethod = $this->Mailer.'Send';
1340                    if (method_exists($this, $sendMethod)) {
1341                        return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
1342                    }
1343
1344                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1345            }
1346        } catch (phpmailerException $exc) {
1347            $this->setError($exc->getMessage());
1348            $this->edebug($exc->getMessage());
1349            if ($this->exceptions) {
1350                throw $exc;
1351            }
1352        }
1353        return false;
1354    }
1355
1356    /**
1357     * Send mail using the $Sendmail program.
1358     * @param string $header The message headers
1359     * @param string $body The message body
1360     * @see PHPMailer::$Sendmail
1361     * @throws phpmailerException
1362     * @access protected
1363     * @return boolean
1364     */
1365    protected function sendmailSend($header, $body)
1366    {
1367        // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1368        if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
1369            if ($this->Mailer == 'qmail') {
1370                $sendmailFmt = '%s -f%s';
1371            } else {
1372                $sendmailFmt = '%s -oi -f%s -t';
1373            }
1374        } else {
1375            if ($this->Mailer == 'qmail') {
1376                $sendmailFmt = '%s';
1377            } else {
1378                $sendmailFmt = '%s -oi -t';
1379            }
1380        }
1381
1382        // TODO: If possible, this should be changed to escapeshellarg.  Needs thorough testing.
1383        $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
1384
1385        if ($this->SingleTo) {
1386            foreach ($this->SingleToArray as $toAddr) {
1387                if (!@$mail = popen($sendmail, 'w')) {
1388                    throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1389                }
1390                fputs($mail, 'To: ' . $toAddr . "\n");
1391                fputs($mail, $header);
1392                fputs($mail, $body);
1393                $result = pclose($mail);
1394                $this->doCallback(
1395                    ($result == 0),
1396                    array($toAddr),
1397                    $this->cc,
1398                    $this->bcc,
1399                    $this->Subject,
1400                    $body,
1401                    $this->From
1402                );
1403                if ($result != 0) {
1404                    throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1405                }
1406            }
1407        } else {
1408            if (!@$mail = popen($sendmail, 'w')) {
1409                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1410            }
1411            fputs($mail, $header);
1412            fputs($mail, $body);
1413            $result = pclose($mail);
1414            $this->doCallback(
1415                ($result == 0),
1416                $this->to,
1417                $this->cc,
1418                $this->bcc,
1419                $this->Subject,
1420                $body,
1421                $this->From
1422            );
1423            if ($result != 0) {
1424                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1425            }
1426        }
1427        return true;
1428    }
1429
1430    /**
1431     * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
1432     *
1433     * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
1434     * @param string $string The string to be validated
1435     * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
1436     * @access protected
1437     * @return boolean
1438     */
1439    protected static function isShellSafe($string)
1440    {
1441        // Future-proof
1442        if (escapeshellcmd($string) !== $string
1443            or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))
1444        ) {
1445            return false;
1446        }
1447
1448        $length = strlen($string);
1449
1450        for ($i = 0; $i < $length; $i++) {
1451            $c = $string[$i];
1452
1453            // All other characters have a special meaning in at least one common shell, including = and +.
1454            // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
1455            // Note that this does permit non-Latin alphanumeric characters based on the current locale.
1456            if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
1457                return false;
1458            }
1459        }
1460
1461        return true;
1462    }
1463
1464    /**
1465     * Send mail using the PHP mail() function.
1466     * @param string $header The …

Large files files are truncated, but you can click here to view the full file