[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/Mail/ -> Mail.php (source)

   1  <?php
   2  
   3  /**
   4   * Joomla! Content Management System
   5   *
   6   * @copyright  (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
   7   * @license    GNU General Public License version 2 or later; see LICENSE.txt
   8   */
   9  
  10  namespace Joomla\CMS\Mail;
  11  
  12  use Joomla\CMS\Factory;
  13  use Joomla\CMS\Language\Text;
  14  use Joomla\CMS\Log\Log;
  15  use Joomla\CMS\Mail\Exception\MailDisabledException;
  16  use PHPMailer\PHPMailer\Exception as phpmailerException;
  17  use PHPMailer\PHPMailer\PHPMailer;
  18  
  19  // phpcs:disable PSR1.Files.SideEffects
  20  \defined('JPATH_PLATFORM') or die;
  21  // phpcs:enable PSR1.Files.SideEffects
  22  
  23  /**
  24   * Email Class.  Provides a common interface to send email from the Joomla! Platform
  25   *
  26   * @since  1.7.0
  27   */
  28  class Mail extends PHPMailer
  29  {
  30      /**
  31       * Mail instances container.
  32       *
  33       * @var    Mail[]
  34       * @since  1.7.3
  35       */
  36      protected static $instances = array();
  37  
  38      /**
  39       * Charset of the message.
  40       *
  41       * @var    string
  42       * @since  1.7.0
  43       */
  44      public $CharSet = 'utf-8';
  45  
  46      /**
  47       * Constructor
  48       *
  49       * @param   boolean  $exceptions  Flag if Exceptions should be thrown
  50       *
  51       * @since   1.7.0
  52       */
  53      public function __construct($exceptions = true)
  54      {
  55          parent::__construct($exceptions);
  56  
  57          // PHPMailer has an issue using the relative path for its language files
  58          $this->setLanguage('en_gb', __DIR__ . '/language/');
  59  
  60          // Configure a callback function to handle errors when $this->debug() is called
  61          $this->Debugoutput = function ($message, $level) {
  62              Log::add(sprintf('Error in Mail API: %s', $message), Log::ERROR, 'mail');
  63          };
  64  
  65          // If debug mode is enabled then set SMTPDebug to the maximum level
  66          if (\defined('JDEBUG') && JDEBUG) {
  67              $this->SMTPDebug = 4;
  68          }
  69  
  70          // Don't disclose the PHPMailer version
  71          $this->XMailer = ' ';
  72  
  73          /**
  74           * Which validator to use by default when validating email addresses.
  75           * Validation patterns supported:
  76           * `auto` Pick best pattern automatically;
  77           * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0;
  78           * `pcre` Use old PCRE implementation;
  79           * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
  80           * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
  81           * `noregex` Don't use a regex: super fast, really dumb.
  82           *
  83           * The default used by phpmailer is `php` but this does not support dotless domains so instead we use `html5`
  84           *
  85           * @see PHPMailer::validateAddress()
  86           *
  87           * @var string|callable
  88           */
  89          PHPMailer::$validator = 'html5';
  90      }
  91  
  92      /**
  93       * Returns the global email object, only creating it if it doesn't already exist.
  94       *
  95       * NOTE: If you need an instance to use that does not have the global configuration
  96       * values, use an id string that is not 'Joomla'.
  97       *
  98       * @param   string   $id          The id string for the Mail instance [optional]
  99       * @param   boolean  $exceptions  Flag if Exceptions should be thrown [optional]
 100       *
 101       * @return  Mail  The global Mail object
 102       *
 103       * @since   1.7.0
 104       */
 105      public static function getInstance($id = 'Joomla', $exceptions = true)
 106      {
 107          if (empty(static::$instances[$id])) {
 108              static::$instances[$id] = new static($exceptions);
 109          }
 110  
 111          return static::$instances[$id];
 112      }
 113  
 114      /**
 115       * Send the mail
 116       *
 117       * @return  boolean  Boolean true if successful, false if exception throwing is disabled.
 118       *
 119       * @since   1.7.0
 120       *
 121       * @throws  MailDisabledException  if the mail function is disabled
 122       * @throws  phpmailerException     if sending failed
 123       */
 124      public function Send()
 125      {
 126          if (!Factory::getApplication()->get('mailonline', 1)) {
 127              throw new MailDisabledException(
 128                  MailDisabledException::REASON_USER_DISABLED,
 129                  Text::_('JLIB_MAIL_FUNCTION_OFFLINE'),
 130                  500
 131              );
 132          }
 133  
 134          if ($this->Mailer === 'mail' && !\function_exists('mail')) {
 135              throw new MailDisabledException(
 136                  MailDisabledException::REASON_MAIL_FUNCTION_NOT_AVAILABLE,
 137                  Text::_('JLIB_MAIL_FUNCTION_DISABLED'),
 138                  500
 139              );
 140          }
 141  
 142          try {
 143              $result = parent::send();
 144          } catch (phpmailerException $e) {
 145              // If auto TLS is disabled just let this bubble up
 146              if (!$this->SMTPAutoTLS) {
 147                  throw $e;
 148              }
 149  
 150              $result = false;
 151          }
 152  
 153          /*
 154           * If sending failed and auto TLS is enabled, retry sending with the feature disabled
 155           *
 156           * See https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting#opportunistic-tls for more info
 157           */
 158          if (!$result && $this->SMTPAutoTLS) {
 159              $this->SMTPAutoTLS = false;
 160  
 161              try {
 162                  $result = parent::send();
 163              } finally {
 164                  // Reset the value for any future emails
 165                  $this->SMTPAutoTLS = true;
 166              }
 167          }
 168  
 169          return $result;
 170      }
 171  
 172      /**
 173       * Set the email sender
 174       *
 175       * @param   mixed  $from  email address and Name of sender
 176       *                        <code>array([0] => email Address, [1] => Name)</code>
 177       *                        or as a string
 178       *
 179       * @return  Mail|boolean  Returns this object for chaining on success or boolean false on failure.
 180       *
 181       * @since   1.7.0
 182       *
 183       * @throws  \UnexpectedValueException  if the sender is not a valid address
 184       * @throws  phpmailerException          if setting the sender failed and exception throwing is enabled
 185       */
 186      public function setSender($from)
 187      {
 188          if (\is_array($from)) {
 189              // If $from is an array we assume it has an address and a name
 190              if (isset($from[2])) {
 191                  // If it is an array with entries, use them
 192                  $result = $this->setFrom(MailHelper::cleanLine($from[0]), MailHelper::cleanLine($from[1]), (bool) $from[2]);
 193              } else {
 194                  $result = $this->setFrom(MailHelper::cleanLine($from[0]), MailHelper::cleanLine($from[1]));
 195              }
 196          } elseif (\is_string($from)) {
 197              // If it is a string we assume it is just the address
 198              $result = $this->setFrom(MailHelper::cleanLine($from));
 199          } else {
 200              // If it is neither, we log a message and throw an exception
 201              Log::add(Text::sprintf('JLIB_MAIL_INVALID_EMAIL_SENDER', $from), Log::WARNING, 'jerror');
 202  
 203              throw new \UnexpectedValueException(sprintf('Invalid email sender: %s', $from));
 204          }
 205  
 206          if ($result === false) {
 207              return false;
 208          }
 209  
 210          return $this;
 211      }
 212  
 213      /**
 214       * Set the email subject
 215       *
 216       * @param   string  $subject  Subject of the email
 217       *
 218       * @return  Mail  Returns this object for chaining.
 219       *
 220       * @since   1.7.0
 221       */
 222      public function setSubject($subject)
 223      {
 224          $this->Subject = MailHelper::cleanLine($subject);
 225  
 226          return $this;
 227      }
 228  
 229      /**
 230       * Set the email body
 231       *
 232       * @param   string  $content  Body of the email
 233       *
 234       * @return  Mail  Returns this object for chaining.
 235       *
 236       * @since   1.7.0
 237       */
 238      public function setBody($content)
 239      {
 240          /*
 241           * Filter the Body
 242           * @todo: Check for XSS
 243           */
 244          $this->Body = MailHelper::cleanText($content);
 245  
 246          return $this;
 247      }
 248  
 249      /**
 250       * Add recipients to the email.
 251       *
 252       * @param   mixed   $recipient  Either a string or array of strings [email address(es)]
 253       * @param   mixed   $name       Either a string or array of strings [name(s)]
 254       * @param   string  $method     The parent method's name.
 255       *
 256       * @return  Mail|boolean  Returns this object for chaining on success or boolean false on failure.
 257       *
 258       * @since   1.7.0
 259       *
 260       * @throws  \InvalidArgumentException if the argument array counts do not match
 261       * @throws  phpmailerException  if setting the address failed and exception throwing is enabled
 262       */
 263      protected function add($recipient, $name = '', $method = 'addAddress')
 264      {
 265          $method = lcfirst($method);
 266  
 267          // If the recipient is an array, add each recipient... otherwise just add the one
 268          if (\is_array($recipient)) {
 269              if (\is_array($name)) {
 270                  $combined = array_combine($recipient, $name);
 271  
 272                  if ($combined === false) {
 273                      throw new \InvalidArgumentException("The number of elements for each array isn't equal.");
 274                  }
 275  
 276                  foreach ($combined as $recipientEmail => $recipientName) {
 277                      $recipientEmail = MailHelper::cleanLine($recipientEmail);
 278                      $recipientName = MailHelper::cleanLine($recipientName);
 279  
 280                      // Check for boolean false return if exception handling is disabled
 281                      if (\call_user_func('parent::' . $method, $recipientEmail, $recipientName) === false) {
 282                          return false;
 283                      }
 284                  }
 285              } else {
 286                  $name = MailHelper::cleanLine($name);
 287  
 288                  foreach ($recipient as $to) {
 289                      $to = MailHelper::cleanLine($to);
 290  
 291                      // Check for boolean false return if exception handling is disabled
 292                      if (\call_user_func('parent::' . $method, $to, $name) === false) {
 293                          return false;
 294                      }
 295                  }
 296              }
 297          } else {
 298              $recipient = MailHelper::cleanLine($recipient);
 299  
 300              // Check for boolean false return if exception handling is disabled
 301              if (\call_user_func('parent::' . $method, $recipient, $name) === false) {
 302                  return false;
 303              }
 304          }
 305  
 306          return $this;
 307      }
 308  
 309      /**
 310       * Add recipients to the email
 311       *
 312       * @param   mixed  $recipient  Either a string or array of strings [email address(es)]
 313       * @param   mixed  $name       Either a string or array of strings [name(s)]
 314       *
 315       * @return  Mail|boolean  Returns this object for chaining on success or false on failure when exception throwing is disabled.
 316       *
 317       * @since   1.7.0
 318       *
 319       * @throws  phpmailerException  if exception throwing is enabled
 320       */
 321      public function addRecipient($recipient, $name = '')
 322      {
 323          return $this->add($recipient, $name, 'addAddress');
 324      }
 325  
 326      /**
 327       * Add carbon copy recipients to the email
 328       *
 329       * @param   mixed  $cc    Either a string or array of strings [email address(es)]
 330       * @param   mixed  $name  Either a string or array of strings [name(s)]
 331       *
 332       * @return  Mail|boolean  Returns this object for chaining on success or boolean false on failure when exception throwing is enabled.
 333       *
 334       * @since   1.7.0
 335       *
 336       * @throws  phpmailerException  if exception throwing is enabled
 337       */
 338      public function addCc($cc, $name = '')
 339      {
 340          // If the carbon copy recipient is an array, add each recipient... otherwise just add the one
 341          if (isset($cc)) {
 342              return $this->add($cc, $name, 'addCC');
 343          }
 344  
 345          return $this;
 346      }
 347  
 348      /**
 349       * Add blind carbon copy recipients to the email
 350       *
 351       * @param   mixed  $bcc   Either a string or array of strings [email address(es)]
 352       * @param   mixed  $name  Either a string or array of strings [name(s)]
 353       *
 354       * @return  Mail|boolean  Returns this object for chaining on success or boolean false on failure when exception throwing is disabled.
 355       *
 356       * @since   1.7.0
 357       *
 358       * @throws  phpmailerException  if exception throwing is enabled
 359       */
 360      public function addBcc($bcc, $name = '')
 361      {
 362          // If the blind carbon copy recipient is an array, add each recipient... otherwise just add the one
 363          if (isset($bcc)) {
 364              return $this->add($bcc, $name, 'addBCC');
 365          }
 366  
 367          return $this;
 368      }
 369  
 370      /**
 371       * Add file attachment to the email
 372       *
 373       * @param   mixed   $path         Either a string or array of strings [filenames]
 374       * @param   mixed   $name         Either a string or array of strings [names]. N.B. if this is an array it must contain the same
 375       *                                number of elements as the array of paths supplied.
 376       * @param   mixed   $encoding     The encoding of the attachment
 377       * @param   mixed   $type         The mime type
 378       * @param   string  $disposition  The disposition of the attachment
 379       *
 380       * @return  Mail|boolean  Returns this object for chaining on success or boolean false on failure when exception throwing is disabled.
 381       *
 382       * @since   3.0.1
 383       * @throws  \InvalidArgumentException  if the argument array counts do not match
 384       * @throws  phpmailerException          if setting the attachment failed and exception throwing is enabled
 385       */
 386      public function addAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream', $disposition = 'attachment')
 387      {
 388          // If the file attachments is an array, add each file... otherwise just add the one
 389          if (isset($path)) {
 390              $result = true;
 391  
 392              if (\is_array($path)) {
 393                  if (!empty($name) && \count($path) != \count($name)) {
 394                      throw new \InvalidArgumentException('The number of attachments must be equal with the number of name');
 395                  }
 396  
 397                  foreach ($path as $key => $file) {
 398                      if (!empty($name)) {
 399                          $result = parent::addAttachment($file, $name[$key], $encoding, $type);
 400                      } else {
 401                          if (!empty($name)) {
 402                              $result = parent::addAttachment($file, $name[$key], $encoding, $type, $disposition);
 403                          } else {
 404                              $result = parent::addAttachment($file, $name, $encoding, $type, $disposition);
 405                          }
 406                      }
 407                  }
 408  
 409                  // Check for boolean false return if exception handling is disabled
 410                  if ($result === false) {
 411                      return false;
 412                  }
 413              } else {
 414                  $result = parent::addAttachment($path, $name, $encoding, $type);
 415              }
 416  
 417              // Check for boolean false return if exception handling is disabled
 418              if ($result === false) {
 419                  return false;
 420              }
 421          }
 422  
 423          return $this;
 424      }
 425  
 426      /**
 427       * Unset all file attachments from the email
 428       *
 429       * @return  Mail  Returns this object for chaining.
 430       *
 431       * @since   3.0.1
 432       */
 433      public function clearAttachments()
 434      {
 435          parent::clearAttachments();
 436  
 437          return $this;
 438      }
 439  
 440      /**
 441       * Unset file attachments specified by array index.
 442       *
 443       * @param   integer  $index  The numerical index of the attachment to remove
 444       *
 445       * @return  Mail  Returns this object for chaining.
 446       *
 447       * @since   3.0.1
 448       */
 449      public function removeAttachment($index = 0)
 450      {
 451          if (isset($this->attachment[$index])) {
 452              unset($this->attachment[$index]);
 453          }
 454  
 455          return $this;
 456      }
 457  
 458      /**
 459       * Add Reply to email address(es) to the email
 460       *
 461       * @param   mixed  $replyto  Either a string or array of strings [email address(es)]
 462       * @param   mixed  $name     Either a string or array of strings [name(s)]
 463       *
 464       * @return  Mail|boolean  Returns this object for chaining on success or boolean false on failure when exception throwing is disabled.
 465       *
 466       * @since   1.7.0
 467       *
 468       * @throws  phpmailerException  if exception throwing is enabled
 469       */
 470      public function addReplyTo($replyto, $name = '')
 471      {
 472          return $this->add($replyto, $name, 'addReplyTo');
 473      }
 474  
 475      /**
 476       * Sets message type to HTML
 477       *
 478       * @param   boolean  $ishtml  Boolean true or false.
 479       *
 480       * @return  Mail  Returns this object for chaining.
 481       *
 482       * @since   3.1.4
 483       */
 484      public function isHtml($ishtml = true)
 485      {
 486          parent::isHTML($ishtml);
 487  
 488          return $this;
 489      }
 490  
 491      /**
 492       * Send messages using $Sendmail.
 493       *
 494       * This overrides the parent class to remove the restriction on the executable's name containing the word "sendmail"
 495       *
 496       * @return  void
 497       *
 498       * @since   1.7.0
 499       */
 500      public function isSendmail()
 501      {
 502          // Prefer the Joomla configured sendmail path and default to the configured PHP path otherwise
 503          $sendmail = Factory::getApplication()->get('sendmail', ini_get('sendmail_path'));
 504  
 505          // And if we still don't have a path, then use the system default for Linux
 506          if (empty($sendmail)) {
 507              $sendmail = '/usr/sbin/sendmail';
 508          }
 509  
 510          $this->Sendmail = $sendmail;
 511          $this->Mailer   = 'sendmail';
 512      }
 513  
 514      /**
 515       * Use sendmail for sending the email
 516       *
 517       * @param   string  $sendmail  Path to sendmail [optional]
 518       *
 519       * @return  boolean  True on success
 520       *
 521       * @since   1.7.0
 522       */
 523      public function useSendmail($sendmail = null)
 524      {
 525          $this->Sendmail = $sendmail;
 526  
 527          if (!empty($this->Sendmail)) {
 528              $this->isSendmail();
 529  
 530              return true;
 531          } else {
 532              $this->isMail();
 533  
 534              return false;
 535          }
 536      }
 537  
 538      /**
 539       * Use SMTP for sending the email
 540       *
 541       * @param   string   $auth    SMTP Authentication [optional]
 542       * @param   string   $host    SMTP Host [optional]
 543       * @param   string   $user    SMTP Username [optional]
 544       * @param   string   $pass    SMTP Password [optional]
 545       * @param   string   $secure  Use secure methods
 546       * @param   integer  $port    The SMTP port
 547       *
 548       * @return  boolean  True on success
 549       *
 550       * @since   1.7.0
 551       */
 552      public function useSmtp($auth = null, $host = null, $user = null, $pass = null, $secure = null, $port = 25)
 553      {
 554          $this->SMTPAuth = $auth;
 555          $this->Host = $host;
 556          $this->Username = $user;
 557          $this->Password = $pass;
 558          $this->Port = $port;
 559  
 560          if ($secure === 'ssl' || $secure === 'tls') {
 561              $this->SMTPSecure = $secure;
 562          }
 563  
 564          if (
 565              ($this->SMTPAuth !== null && $this->Host !== null && $this->Username !== null && $this->Password !== null)
 566              || ($this->SMTPAuth === null && $this->Host !== null)
 567          ) {
 568              $this->isSMTP();
 569  
 570              return true;
 571          } else {
 572              $this->isMail();
 573  
 574              return false;
 575          }
 576      }
 577  
 578      /**
 579       * Function to send an email
 580       *
 581       * @param   string   $from         From email address
 582       * @param   string   $fromName     From name
 583       * @param   mixed    $recipient    Recipient email address(es)
 584       * @param   string   $subject      email subject
 585       * @param   string   $body         Message body
 586       * @param   boolean  $mode         false = plain text, true = HTML
 587       * @param   mixed    $cc           CC email address(es)
 588       * @param   mixed    $bcc          BCC email address(es)
 589       * @param   mixed    $attachment   Attachment file name(s)
 590       * @param   mixed    $replyTo      Reply to email address(es)
 591       * @param   mixed    $replyToName  Reply to name(s)
 592       *
 593       * @return  boolean  True on success, false on failure when exception throwing is disabled.
 594       *
 595       * @since   1.7.0
 596       *
 597       * @throws  MailDisabledException  if the mail function is disabled
 598       * @throws  phpmailerException     if exception throwing is enabled
 599       */
 600      public function sendMail(
 601          $from,
 602          $fromName,
 603          $recipient,
 604          $subject,
 605          $body,
 606          $mode = false,
 607          $cc = null,
 608          $bcc = null,
 609          $attachment = null,
 610          $replyTo = null,
 611          $replyToName = null
 612      ) {
 613          // Create config object
 614          $app = Factory::getApplication();
 615  
 616          $this->setSubject($subject);
 617          $this->setBody($body);
 618  
 619          // Are we sending the email as HTML?
 620          $this->isHtml($mode);
 621  
 622          /*
 623           * Do not send the message if adding any of the below items fails
 624           */
 625  
 626          if ($this->addRecipient($recipient) === false) {
 627              return false;
 628          }
 629  
 630          if ($this->addCc($cc) === false) {
 631              return false;
 632          }
 633  
 634          if ($this->addBcc($bcc) === false) {
 635              return false;
 636          }
 637  
 638          if ($this->addAttachment($attachment) === false) {
 639              return false;
 640          }
 641  
 642          // Take care of reply email addresses
 643          if (\is_array($replyTo)) {
 644              $numReplyTo = \count($replyTo);
 645  
 646              for ($i = 0; $i < $numReplyTo; $i++) {
 647                  if ($this->addReplyTo($replyTo[$i], $replyToName[$i]) === false) {
 648                      return false;
 649                  }
 650              }
 651          } elseif (isset($replyTo)) {
 652              if ($this->addReplyTo($replyTo, $replyToName) === false) {
 653                  return false;
 654              }
 655          } elseif ($app->get('replyto')) {
 656              $this->addReplyTo($app->get('replyto'), $app->get('replytoname'));
 657          }
 658  
 659          // Add sender to replyTo only if no replyTo received
 660          $autoReplyTo = empty($this->ReplyTo);
 661  
 662          if ($this->setSender(array($from, $fromName, $autoReplyTo)) === false) {
 663              return false;
 664          }
 665  
 666          return $this->Send();
 667      }
 668  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer