File manager - Edit - /home/opticamezl/www/newok/Mail.tar
Back
Mail.php 0000644 00000053336 15172602777 0006167 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Mail; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; use Joomla\CMS\Mail\Exception\MailDisabledException; use PHPMailer\PHPMailer\Exception as phpmailerException; use PHPMailer\PHPMailer\PHPMailer; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Email Class. Provides a common interface to send email from the Joomla! Platform * * @since 1.7.0 */ class Mail extends PHPMailer implements MailerInterface { /** * Mail instances container. * * @var Mail[] * @since 1.7.3 * * @deprecated 4.4.0 will be removed in 6.0 * See getInstance() for more details */ public static $instances = []; /** * Charset of the message. * * @var string * @since 1.7.0 */ public $CharSet = 'utf-8'; /** * Constructor * * @param boolean $exceptions Flag if Exceptions should be thrown * * @since 1.7.0 */ public function __construct($exceptions = true) { parent::__construct($exceptions); // PHPMailer has an issue using the relative path for its language files $this->setLanguage('en_gb', __DIR__ . '/language/'); // Configure a callback function to handle errors when $this->debug() is called $this->Debugoutput = function ($message, $level) { Log::add(sprintf('Error in Mail API: %s', $message), Log::ERROR, 'mail'); }; // If debug mode is enabled then set SMTPDebug to the maximum level if (\defined('JDEBUG') && JDEBUG) { $this->SMTPDebug = 4; } // Don't disclose the PHPMailer version $this->XMailer = ' '; /** * Which validator to use by default when validating email addresses. * Validation patterns supported: * `auto` Pick best pattern automatically; * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0; * `pcre` Use old PCRE implementation; * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. * `noregex` Don't use a regex: super fast, really dumb. * * The default used by phpmailer is `php` but this does not support dotless domains so instead we use `html5` * * @see PHPMailer::validateAddress() * * @var string|callable */ PHPMailer::$validator = 'html5'; } /** * Returns the global email object, only creating it if it doesn't already exist. * * NOTE: If you need an instance to use that does not have the global configuration * values, use an id string that is not 'Joomla'. * * @param string $id The id string for the Mail instance [optional] * @param boolean $exceptions Flag if Exceptions should be thrown [optional] * * @return Mail The global Mail object * * @since 4.4.0 * * @deprecated 4.4.0 will be removed in 6.0 * Use the mailer service in the DI container and create a mailer from there * Example: * Factory::getContainer()->get(MailerFactoryInterface::class)->createMailer(); */ public static function getInstance($id = 'Joomla', $exceptions = true) { if (empty(static::$instances[$id])) { $config = clone Factory::getConfig(); $config->set('throw_exceptions', $exceptions); static::$instances[$id] = Factory::getContainer()->get(MailerFactoryInterface::class)->createMailer($config); } return static::$instances[$id]; } /** * Send the mail * * @return boolean Boolean true if successful, false if exception throwing is disabled. * * @since 1.7.0 * * @throws MailDisabledException if the mail function is disabled * @throws phpmailerException if sending failed */ public function Send() { if (!Factory::getApplication()->get('mailonline', 1)) { throw new MailDisabledException( MailDisabledException::REASON_USER_DISABLED, Text::_('JLIB_MAIL_FUNCTION_OFFLINE'), 500 ); } if ($this->Mailer === 'mail' && !\function_exists('mail')) { throw new MailDisabledException( MailDisabledException::REASON_MAIL_FUNCTION_NOT_AVAILABLE, Text::_('JLIB_MAIL_FUNCTION_DISABLED'), 500 ); } try { $result = parent::send(); } catch (phpmailerException $e) { // If auto TLS is disabled just let this bubble up if (!$this->SMTPAutoTLS) { throw $e; } $result = false; } /* * If sending failed and auto TLS is enabled, retry sending with the feature disabled * * See https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting#opportunistic-tls for more info */ if (!$result && $this->SMTPAutoTLS) { $this->SMTPAutoTLS = false; try { $result = parent::send(); } finally { // Reset the value for any future emails $this->SMTPAutoTLS = true; } } return $result; } /** * Set the email sender * * @param mixed $from email address and Name of sender * <code>array([0] => email Address, [1] => Name)</code> * or as a string * @param mixed $name Either a string or array of strings [name(s)] * * @return Mail|boolean Returns this object for chaining on success or boolean false on failure. * * @since 1.7.0 * * @throws \UnexpectedValueException if the sender is not a valid address * @throws phpmailerException if setting the sender failed and exception throwing is enabled */ public function setSender($from, $name = '') { if (\is_array($from)) { // If $from is an array we assume it has an address and a name if (isset($from[2])) { // If it is an array with entries, use them $result = $this->setFrom(MailHelper::cleanLine($from[0]), MailHelper::cleanLine($from[1]), (bool) $from[2]); } else { $result = $this->setFrom(MailHelper::cleanLine($from[0]), MailHelper::cleanLine($from[1])); } } elseif (\is_string($from)) { // If it is a string we assume it is just the address $result = $this->setFrom(MailHelper::cleanLine($from), $name); } else { // If it is neither, we log a message and throw an exception Log::add(Text::sprintf('JLIB_MAIL_INVALID_EMAIL_SENDER', $from), Log::WARNING, 'jerror'); throw new \UnexpectedValueException(sprintf('Invalid email sender: %s', $from)); } if ($result === false) { return false; } return $this; } /** * Set the email subject * * @param string $subject Subject of the email * * @return Mail Returns this object for chaining. * * @since 1.7.0 */ public function setSubject($subject) { $this->Subject = MailHelper::cleanSubject($subject); return $this; } /** * Set the email body * * @param string $content Body of the email * * @return Mail Returns this object for chaining. * * @since 1.7.0 */ public function setBody($content) { /* * Filter the Body * @todo: Check for XSS */ $this->Body = MailHelper::cleanText($content); return $this; } /** * Add recipients to the email. * * @param mixed $recipient Either a string or array of strings [email address(es)] * @param mixed $name Either a string or array of strings [name(s)] * @param string $method The parent method's name. * * @return Mail|boolean Returns this object for chaining on success or boolean false on failure. * * @since 1.7.0 * * @throws \InvalidArgumentException if the argument array counts do not match * @throws phpmailerException if setting the address failed and exception throwing is enabled */ protected function add($recipient, $name = '', $method = 'addAddress') { $method = lcfirst($method); // If the recipient is an array, add each recipient... otherwise just add the one if (\is_array($recipient)) { if (\is_array($name)) { $combined = array_combine($recipient, $name); if ($combined === false) { throw new \InvalidArgumentException("The number of elements for each array isn't equal."); } foreach ($combined as $recipientEmail => $recipientName) { $recipientEmail = MailHelper::cleanLine($recipientEmail); $recipientName = MailHelper::cleanLine($recipientName); // Check for boolean false return if exception handling is disabled if (\call_user_func([parent::class, $method], $recipientEmail, $recipientName) === false) { return false; } } } else { $name = MailHelper::cleanLine($name); foreach ($recipient as $to) { $to = MailHelper::cleanLine($to); // Check for boolean false return if exception handling is disabled if (\call_user_func([parent::class, $method], $to, $name) === false) { return false; } } } } else { $recipient = MailHelper::cleanLine($recipient); // Check for boolean false return if exception handling is disabled if (\call_user_func([parent::class, $method], $recipient, $name) === false) { return false; } } return $this; } /** * Add recipients to the email * * @param mixed $recipient Either a string or array of strings [email address(es)] * @param mixed $name Either a string or array of strings [name(s)] * * @return Mail|boolean Returns this object for chaining on success or false on failure when exception throwing is disabled. * * @since 1.7.0 * * @throws phpmailerException if exception throwing is enabled */ public function addRecipient($recipient, $name = '') { return $this->add($recipient, $name, 'addAddress'); } /** * Add carbon copy recipients to the email * * @param mixed $cc Either a string or array of strings [email address(es)] * @param mixed $name Either a string or array of strings [name(s)] * * @return Mail|boolean Returns this object for chaining on success or boolean false on failure when exception throwing is enabled. * * @since 1.7.0 * * @throws phpmailerException if exception throwing is enabled */ public function addCc($cc, $name = '') { // If the carbon copy recipient is an array, add each recipient... otherwise just add the one if (isset($cc)) { return $this->add($cc, $name, 'addCC'); } return $this; } /** * Add blind carbon copy recipients to the email * * @param mixed $bcc Either a string or array of strings [email address(es)] * @param mixed $name Either a string or array of strings [name(s)] * * @return Mail|boolean Returns this object for chaining on success or boolean false on failure when exception throwing is disabled. * * @since 1.7.0 * * @throws phpmailerException if exception throwing is enabled */ public function addBcc($bcc, $name = '') { // If the blind carbon copy recipient is an array, add each recipient... otherwise just add the one if (isset($bcc)) { return $this->add($bcc, $name, 'addBCC'); } return $this; } /** * Add file attachment to the email * * @param mixed $path Either a string or array of strings [filenames] * @param mixed $name Either a string or array of strings [names]. N.B. if this is an array it must contain the same * number of elements as the array of paths supplied. * @param mixed $encoding The encoding of the attachment * @param mixed $type The mime type * @param string $disposition The disposition of the attachment * * @return Mail|boolean Returns this object for chaining on success or boolean false on failure when exception throwing is disabled. * * @since 3.0.1 * @throws \InvalidArgumentException if the argument array counts do not match * @throws phpmailerException if setting the attachment failed and exception throwing is enabled */ public function addAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream', $disposition = 'attachment') { // If the file attachments is an array, add each file... otherwise just add the one if (isset($path)) { $result = true; if (\is_array($path)) { if (!empty($name) && \count($path) != \count($name)) { throw new \InvalidArgumentException('The number of attachments must be equal with the number of name'); } foreach ($path as $key => $file) { if (!empty($name)) { $result = parent::addAttachment($file, $name[$key], $encoding, $type); } else { if (!empty($name)) { $result = parent::addAttachment($file, $name[$key], $encoding, $type, $disposition); } else { $result = parent::addAttachment($file, $name, $encoding, $type, $disposition); } } } // Check for boolean false return if exception handling is disabled if ($result === false) { return false; } } else { $result = parent::addAttachment($path, $name, $encoding, $type); } // Check for boolean false return if exception handling is disabled if ($result === false) { return false; } } return $this; } /** * Unset all file attachments from the email * * @return Mail Returns this object for chaining. * * @since 3.0.1 */ public function clearAttachments() { parent::clearAttachments(); return $this; } /** * Unset file attachments specified by array index. * * @param integer $index The numerical index of the attachment to remove * * @return Mail Returns this object for chaining. * * @since 3.0.1 */ public function removeAttachment($index = 0) { if (isset($this->attachment[$index])) { unset($this->attachment[$index]); } return $this; } /** * Add Reply to email address(es) to the email * * @param mixed $replyto Either a string or array of strings [email address(es)] * @param mixed $name Either a string or array of strings [name(s)] * * @return Mail|boolean Returns this object for chaining on success or boolean false on failure when exception throwing is disabled. * * @since 1.7.0 * * @throws phpmailerException if exception throwing is enabled */ public function addReplyTo($replyto, $name = '') { return $this->add($replyto, $name, 'addReplyTo'); } /** * Sets message type to HTML * * @param boolean $ishtml Boolean true or false. * * @return Mail Returns this object for chaining. * * @since 3.1.4 */ public function isHtml($ishtml = true) { parent::isHTML($ishtml); return $this; } /** * Send messages using $Sendmail. * * This overrides the parent class to remove the restriction on the executable's name containing the word "sendmail" * * @return void * * @since 1.7.0 */ public function isSendmail() { // Prefer the Joomla configured sendmail path and default to the configured PHP path otherwise $sendmail = Factory::getApplication()->get('sendmail', ini_get('sendmail_path')); // And if we still don't have a path, then use the system default for Linux if (empty($sendmail)) { $sendmail = '/usr/sbin/sendmail'; } $this->Sendmail = $sendmail; $this->Mailer = 'sendmail'; } /** * Use sendmail for sending the email * * @param string $sendmail Path to sendmail [optional] * * @return boolean True on success * * @since 1.7.0 */ public function useSendmail($sendmail = null) { $this->Sendmail = $sendmail; if (!empty($this->Sendmail)) { $this->isSendmail(); return true; } else { $this->isMail(); return false; } } /** * Use SMTP for sending the email * * @param string $auth SMTP Authentication [optional] * @param string $host SMTP Host [optional] * @param string $user SMTP Username [optional] * @param string $pass SMTP Password [optional] * @param string $secure Use secure methods * @param integer $port The SMTP port * * @return boolean True on success * * @since 1.7.0 */ public function useSmtp($auth = null, $host = null, $user = null, $pass = null, $secure = null, $port = 25) { $this->SMTPAuth = $auth; $this->Host = $host; $this->Username = $user; $this->Password = $pass; $this->Port = $port; if ($secure === 'ssl' || $secure === 'tls') { $this->SMTPSecure = $secure; } if ( ($this->SMTPAuth !== null && $this->Host !== null && $this->Username !== null && $this->Password !== null) || ($this->SMTPAuth === null && $this->Host !== null) ) { $this->isSMTP(); return true; } else { $this->isMail(); return false; } } /** * Function to send an email * * @param string $from From email address * @param string $fromName From name * @param mixed $recipient Recipient email address(es) * @param string $subject email subject * @param string $body Message body * @param boolean $mode false = plain text, true = HTML * @param mixed $cc CC email address(es) * @param mixed $bcc BCC email address(es) * @param mixed $attachment Attachment file name(s) * @param mixed $replyTo Reply to email address(es) * @param mixed $replyToName Reply to name(s) * * @return boolean True on success, false on failure when exception throwing is disabled. * * @since 1.7.0 * * @throws MailDisabledException if the mail function is disabled * @throws phpmailerException if exception throwing is enabled */ public function sendMail( $from, $fromName, $recipient, $subject, $body, $mode = false, $cc = null, $bcc = null, $attachment = null, $replyTo = null, $replyToName = null ) { // Create config object $app = Factory::getApplication(); $this->setSubject($subject); $this->setBody($body); // Are we sending the email as HTML? $this->isHtml($mode); /* * Do not send the message if adding any of the below items fails */ if ($this->addRecipient($recipient) === false) { return false; } if ($this->addCc($cc) === false) { return false; } if ($this->addBcc($bcc) === false) { return false; } if ($this->addAttachment($attachment) === false) { return false; } // Take care of reply email addresses if (\is_array($replyTo)) { $numReplyTo = \count($replyTo); for ($i = 0; $i < $numReplyTo; $i++) { if ($this->addReplyTo($replyTo[$i], $replyToName[$i]) === false) { return false; } } } elseif (isset($replyTo)) { if ($this->addReplyTo($replyTo, $replyToName) === false) { return false; } } elseif ($app->get('replyto')) { $this->addReplyTo($app->get('replyto'), $app->get('replytoname')); } // Add sender to replyTo only if no replyTo received $autoReplyTo = empty($this->ReplyTo); if ($this->setSender([$from, $fromName, $autoReplyTo]) === false) { return false; } return $this->Send(); } } MailerFactoryInterface.php 0000644 00000001546 15172602777 0011663 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Mail; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Interface defining a factory which can create mailer objects. * * @since 4.4.0 */ interface MailerFactoryInterface { /** * Method to get an instance of a mailer. If the passed settings are null, * then the mailer does use the internal configuration. * * @param ?Registry $settings The configuration * * @return MailerInterface * * @since 4.4.0 */ public function createMailer(?Registry $settings = null): MailerInterface; } MailHelper.php 0000644 00000017306 15172602777 0007324 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2007 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Mail; use Joomla\CMS\Router\Route; use Joomla\CMS\String\PunycodeHelper; use Joomla\CMS\Uri\Uri; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Email helper class, provides static methods to perform various tasks relevant * to the Joomla email routines. * * @todo: Test these methods as the regex work is first run and not tested thoroughly * * @since 1.7.0 */ abstract class MailHelper { /** * Cleans single line inputs. * * @param string $value String to be cleaned. * * @return string Cleaned string. * * @since 1.7.0 */ public static function cleanLine($value) { $value = PunycodeHelper::emailToPunycode($value); return trim(preg_replace('/(%0A|%0D|\n+|\r+)/i', '', $value)); } /** * Cleans multi-line inputs. * * @param string $value Multi-line string to be cleaned. * * @return string Cleaned multi-line string. * * @since 1.7.0 */ public static function cleanText($value) { return trim(preg_replace('/(%0A|%0D|\n+|\r+)(content-type:|to:|cc:|bcc:)/i', '', $value)); } /** * Cleans any injected headers from the email body. * * @param string $body email body string. * * @return string Cleaned email body string. * * @since 1.7.0 */ public static function cleanBody($body) { // Strip all email headers from a string return preg_replace("/((From:|To:|Cc:|Bcc:|Subject:|Content-type:) ([\S]+))/", '', $body); } /** * Cleans any injected headers from the subject string. * * @param string $subject email subject string. * * @return string Cleaned email subject string. * * @since 1.7.0 */ public static function cleanSubject($subject) { return preg_replace("/((From:|To:|Cc:|Bcc:|Content-type:) ([\S]+))/", '', $subject); } /** * Verifies that an email address does not have any extra headers injected into it. * * @param string $address email address. * * @return mixed email address string or boolean false if injected headers are present. * * @since 1.7.0 */ public static function cleanAddress($address) { if (preg_match("[\s;,]", $address)) { return false; } return $address; } /** * Verifies that the string is in a proper email address format. * * @param string $email String to be verified. * * @return boolean True if string has the correct format; false otherwise. * * @since 1.7.0 */ public static function isEmailAddress($email) { // Split the email into a local and domain $atIndex = strrpos($email, '@'); $domain = substr($email, $atIndex + 1); $local = substr($email, 0, $atIndex); // Check Length of domain $domainLen = \strlen($domain); if ($domainLen < 1 || $domainLen > 255) { return false; } /* * Check the local address * We're a bit more conservative about what constitutes a "legal" address, that is, a-zA-Z0-9.!#$%&'*+/=?^_`{|}~- * The first and last character in local cannot be a period ('.') * Also, period should not appear 2 or more times consecutively */ $allowed = "a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-"; $regex = "/^[$allowed][\.$allowed]{0,63}$/"; if (!preg_match($regex, $local) || substr($local, -1) === '.' || $local[0] === '.' || preg_match('/\.\./', $local)) { return false; } // No problem if the domain looks like an IP address, ish $regex = '/^[0-9\.]+$/'; if (preg_match($regex, $domain)) { return true; } // Check Lengths $localLen = \strlen($local); if ($localLen < 1 || $localLen > 64) { return false; } // Check the domain $domain_array = explode('.', $domain); $regex = '/^[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/'; foreach ($domain_array as $domain) { // Convert domain to punycode $domain = PunycodeHelper::toPunycode($domain); // Must be something if (!$domain) { return false; } // Check for invalid characters if (!preg_match($regex, $domain)) { return false; } // Check for a dash at the beginning of the domain if (strpos($domain, '-') === 0) { return false; } // Check for a dash at the end of the domain $length = \strlen($domain) - 1; if (strpos($domain, '-', $length) === $length) { return false; } } return true; } /** * Convert relative (links, images sources) to absolute urls so that content is accessible in email * * @param string $content The content need to convert * * @return string The converted content which the relative urls are converted to absolute urls * * @since 4.1.0 */ public static function convertRelativeToAbsoluteUrls($content) { $siteUrl = Uri::root(); // Replace none SEF URLs by absolute SEF URLs if (strpos($content, 'href="index.php?') !== false) { preg_match_all('#href="index.php\?([^"]+)"#m', $content, $matches); foreach ($matches[1] as $urlQueryString) { $content = str_replace( 'href="index.php?' . $urlQueryString . '"', 'href="' . Route::link('site', 'index.php?' . $urlQueryString, Route::TLS_IGNORE, true) . '"', $content ); } self::checkContent($content); } // Replace relative links, image sources with absolute Urls $protocols = '[a-zA-Z0-9\-]+:'; $attributes = ['href=', 'src=', 'poster=']; foreach ($attributes as $attribute) { if (strpos($content, $attribute) !== false) { $regex = '#\s' . $attribute . '"(?!/|' . $protocols . '|\#|\')([^"]*)"#m'; $content = preg_replace($regex, ' ' . $attribute . '"' . $siteUrl . '$1"', $content); self::checkContent($content); } } return $content; } /** * Check the content after regular expression function call. * * @param string $content Content to be checked. * * @return void * * @throws \RuntimeException If there is an error in previous regular expression function call. * @since 4.1.0 */ private static function checkContent($content) { if ($content !== null) { return; } switch (preg_last_error()) { case PREG_BACKTRACK_LIMIT_ERROR: $message = 'PHP regular expression limit reached (pcre.backtrack_limit)'; break; case PREG_RECURSION_LIMIT_ERROR: $message = 'PHP regular expression limit reached (pcre.recursion_limit)'; break; case PREG_BAD_UTF8_ERROR: $message = 'Bad UTF8 passed to PCRE function'; break; default: $message = 'Unknown PCRE error calling PCRE function'; } throw new \RuntimeException($message); } } MailerFactoryAwareInterface.php 0000644 00000001414 15172602777 0012635 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Mail; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Interface to be implemented by classes depending on a mailer factory. * * @since 4.4.0 */ interface MailerFactoryAwareInterface { /** * Set the mailer factory to use. * * @param ?MailerFactoryInterface $mailerFactory The mailer factory to use. * * @return void * * @since 4.4.0 */ public function setMailerFactory(?MailerFactoryInterface $mailerFactory = null): void; } language/phpmailer.lang-en_gb.php 0000644 00000003342 15172602777 0013031 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2007 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('JPATH_PLATFORM') or die; use Joomla\CMS\Language\Text; $PHPMAILER_LANG['authenticate'] = Text::_('PHPMAILER_AUTHENTICATE'); $PHPMAILER_LANG['connect_host'] = Text::_('PHPMAILER_CONNECT_HOST'); $PHPMAILER_LANG['data_not_accepted'] = Text::_('PHPMAILER_DATA_NOT_ACCEPTED'); $PHPMAILER_LANG['empty_message'] = Text::_('PHPMAILER_EMPTY_MESSAGE'); $PHPMAILER_LANG['encoding'] = Text::_('PHPMAILER_ENCODING'); $PHPMAILER_LANG['execute'] = Text::_('PHPMAILER_EXECUTE'); $PHPMAILER_LANG['file_access'] = Text::_('PHPMAILER_FILE_ACCESS'); $PHPMAILER_LANG['file_open'] = Text::_('PHPMAILER_FILE_OPEN'); $PHPMAILER_LANG['from_failed'] = Text::_('PHPMAILER_FROM_FAILED'); $PHPMAILER_LANG['instantiate'] = Text::_('PHPMAILER_INSTANTIATE'); $PHPMAILER_LANG['invalid_address'] = Text::_('PHPMAILER_INVALID_ADDRESS'); $PHPMAILER_LANG['mailer_not_supported'] = Text::_('PHPMAILER_MAILER_IS_NOT_SUPPORTED'); $PHPMAILER_LANG['provide_address'] = Text::_('PHPMAILER_PROVIDE_ADDRESS'); $PHPMAILER_LANG['recipients_failed'] = Text::_('PHPMAILER_RECIPIENTS_FAILED'); $PHPMAILER_LANG['signing'] = Text::_('PHPMAILER_SIGNING_ERROR'); $PHPMAILER_LANG['smtp_connect_failed'] = Text::_('PHPMAILER_SMTP_CONNECT_FAILED'); $PHPMAILER_LANG['smtp_error'] = Text::_('PHPMAILER_SMTP_ERROR'); $PHPMAILER_LANG['variable_set'] = Text::_('PHPMAILER_VARIABLE_SET'); $PHPMAILER_LANG['extension_missing'] = Text::_('PHPMAILER_EXTENSION_MISSING'); MailerFactory.php 0000644 00000006357 15172602777 0010047 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Mail; use Exception; use Joomla\CMS\Log\Log; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Default factory for creating mailer objects. * * @since 4.4.0 */ class MailerFactory implements MailerFactoryInterface { /** * The default configuration. * * @var Registry * @since 4.4.0 */ private $defaultConfiguration; /** * The MailerFactory constructor. * * @param Registry $defaultConfiguration The default configuration */ public function __construct(Registry $defaultConfiguration) { $this->defaultConfiguration = $defaultConfiguration; } /** * Method to get an instance of a mailer. If the passed settings are null, * then the mailer does use the internal configuration. * * @param ?Registry $settings The configuration * * @return MailerInterface * * @since 4.4.0 */ public function createMailer(?Registry $settings = null): MailerInterface { $configuration = new Registry($this->defaultConfiguration); if ($settings) { $configuration->merge($settings); } $mailer = new Mail((bool) $configuration->get('throw_exceptions', true)); $smtpauth = $configuration->get('smtpauth') == 0 ? null : 1; $smtpuser = $configuration->get('smtpuser'); $smtppass = $configuration->get('smtppass'); $smtphost = $configuration->get('smtphost'); $smtpsecure = $configuration->get('smtpsecure'); $smtpport = $configuration->get('smtpport'); $mailfrom = $configuration->get('mailfrom'); $fromname = $configuration->get('fromname'); $mailType = $configuration->get('mailer'); // Clean the email address $mailfrom = MailHelper::cleanLine($mailfrom); // Set default sender without Reply-to if the mailfrom is a valid address if (MailHelper::isEmailAddress($mailfrom)) { // Wrap in try/catch to catch Exception if it is throwing them try { // Check for a false return value if exception throwing is disabled if ($mailer->setFrom($mailfrom, MailHelper::cleanLine($fromname), false) === false) { Log::add(__METHOD__ . '() could not set the sender data.', Log::WARNING, 'mail'); } } catch (\Exception $e) { Log::add(__METHOD__ . '() could not set the sender data.', Log::WARNING, 'mail'); } } // Default mailer is to use PHP's mail function switch ($mailType) { case 'smtp': $mailer->useSmtp($smtpauth, $smtphost, $smtpuser, $smtppass, $smtpsecure, $smtpport); break; case 'sendmail': $mailer->isSendmail(); break; default: $mailer->isMail(); break; } return $mailer; } } Exception/MailDisabledException.php 0000644 00000003441 15172602777 0013424 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Mail\Exception; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Exception class defining an error for disabled mail functionality. * * @since 4.0.0 */ final class MailDisabledException extends \RuntimeException { /** * Send Mail option is disabled by the user. * * @var string * @since 4.0.0 */ public const REASON_USER_DISABLED = 'user_disabled'; /** * Mail() function is not available on the system. * * @var string * @since 4.0.0 */ public const REASON_MAIL_FUNCTION_NOT_AVAILABLE = 'mail_function_not_available'; /** * Reason mail is disabled. * * @var string * @since 4.0.0 */ private $reason; /** * Constructor. * * @param string $reason The reason why mail is disabled. * @param string $message The Exception message to throw. * @param integer $code The Exception code. * @param \Throwable $previous The previous exception used for the exception chaining. * * @since 4.0.0 */ public function __construct(string $reason, string $message = '', int $code = 0, \Throwable $previous = null) { parent::__construct($message, $code, $previous); $this->reason = $reason; } /** * Method to return the reason why mail is disabled. * * @return string * * @since 4.0.0 */ public function getReason(): string { return $this->reason; } } MailerInterface.php 0000644 00000007137 15172602777 0010335 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Mail; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Provides a common interface to send emails with. * * @since 4.4.0 */ interface MailerInterface { /** * Send the mail. Throws an exception when something goes wrong. * * @return void * * @since 4.4.0 * * @throws \RuntimeException */ public function send(); /** * Set the email sender. * * @param string $fromEmail The Email address of the sender * @param string $name The name of the sender * * @return void * * @since 4.4.0 * * @throws \UnexpectedValueException if the sender is not a valid address */ public function setSender(string $fromEmail, string $name = ''); /** * Set the email subject. * * @param string $subject Subject of the email * * @return void * * @since 4.4.0 */ public function setSubject(string $subject); /** * Set the email body. * * @param string $content Body of the email * * @return void * * @since 4.4.0 */ public function setBody(string $content); /** * Add a recipient to the email. * * @param string $recipientEmail The email of the recipient * @param string $name The name of the recipient * * @return void * * @since 4.4.0 * * @throws \UnexpectedValueException if the recipient is not a valid address */ public function addRecipient(string $recipientEmail, string $name = ''); /** * Add a carbon copy recipient to the email. * * @param string $ccEmail The email of the CC recipient * @param string $name The name of the CC recipient * * @return void * * @since 4.4.0 * * @throws \UnexpectedValueException if the CC is not a valid address */ public function addCc(string $ccEmail, string $name = ''); /** * Add a blind carbon copy recipient to the email. * * @param string $bccEmail The email of the BCC recipient * @param string $name The name of the BCC recipient * * @return void * * @since 4.4.0 * * @throws \UnexpectedValueException if the BCC is not a valid address */ public function addBcc(string $bccEmail, string $name = ''); /** * Add file attachment to the email. * * @param string $data The data of the attachment * @param string $name The name of the attachment * @param string $encoding The encoding of the attachment * @param string $type The mime type of the attachment * * @return void * * @since 4.4.0 */ public function addAttachment(string $data, string $name = '', string $encoding = 'base64', string $type = 'application/octet-stream'); /** * Add Reply to email address to the email * * @param string $replyToEmail The email of the reply address * @param string $name The name of the reply address * * @return void * * @since 4.4.0 * * @throws \UnexpectedValueException if the replay to is not a valid address */ public function addReplyTo(string $replyToEmail, string $name = ''); } MailTemplate.php 0000644 00000042611 15172602777 0007655 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Mail; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\File; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Language\Text; use Joomla\CMS\Mail\Exception\MailDisabledException; use Joomla\Database\ParameterType; use Joomla\Registry\Registry; use PHPMailer\PHPMailer\Exception as phpmailerException; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Email Templating Class * * @since 4.0.0 */ class MailTemplate { /** * Mailer object to send the actual mail. * * @var \Joomla\CMS\Mail\Mail * @since 4.0.0 */ protected $mailer; /** * Identifier of the mail template. * * @var string * @since 4.0.0 */ protected $template_id; /** * Language of the mail template. * * @var string */ protected $language; /** * * @var string[] * @since 4.0.0 */ protected $data = []; /** * * @var string[] * @since 4.4.7 */ protected $unsafe_tags = []; /** * * @var string[] * @since 4.0.0 */ protected $attachments = []; /** * List of recipients of the email * * @var \stdClass[] * @since 4.0.0 */ protected $recipients = []; /** * Reply To of the email * * @var \stdClass * @since 4.0.0 */ protected $replyto; /** * Constructor for the mail templating class * * @param string $templateId Id of the mail template. * @param string $language Language of the template to use. * @param Mail $mailer Mail object to send the mail with. * * @since 4.0.0 */ public function __construct($templateId, $language, Mail $mailer = null) { $this->template_id = $templateId; $this->language = $language; if ($mailer) { $this->mailer = $mailer; } else { $this->mailer = Factory::getMailer(); } } /** * Add an attachment to the mail * * @param string $name Filename of the attachment * @param string $file Either a filepath or filecontent * * @return void * * @since 4.0.0 */ public function addAttachment($name, $file) { $attachment = new \stdClass(); $attachment->name = $name; $attachment->file = $file; $this->attachments[] = $attachment; } /** * Adds recipients for this mail * * @param string $mail Mail address of the recipient * @param string $name Name of the recipient * @param string $type How should the recipient receive the mail? ('to', 'cc', 'bcc') * * @return void * * @since 4.0.0 */ public function addRecipient($mail, $name = null, $type = 'to') { $recipient = new \stdClass(); $recipient->mail = $mail; $recipient->name = $name ?? $mail; $recipient->type = $type; $this->recipients[] = $recipient; } /** * Set reply to for this mail * * @param string $mail Mail address to reply to * @param string $name Name * * @return void * * @since 4.0.0 */ public function setReplyTo($mail, $name = '') { $reply = new \stdClass(); $reply->mail = $mail; $reply->name = $name; $this->replyto = $reply; } /** * Add data to replace in the template * * @param array $data Associative array of strings to replace * * @return void * * @since 4.0.0 */ public function addTemplateData($data) { $this->data = array_merge($this->data, $data); } /** * Mark tags as unsafe to ensure escaping in HTML mails * * @param array $tags Tag names * * @return void * * @since 4.4.7 */ public function addUnsafeTags($tags) { $this->unsafe_tags = array_merge($this->unsafe_tags, array_map('strtoupper', $tags)); } /** * Render and send the mail * * @return boolean True on success * * @since 4.0.0 * @throws \Exception * @throws MailDisabledException * @throws phpmailerException */ public function send() { $config = ComponentHelper::getParams('com_mails'); $mail = self::getTemplate($this->template_id, $this->language); // If the Mail Template was not found in the db, we cannot send an email. if ($mail === null) { return false; } /** @var Registry $params */ $params = $mail->params; $app = Factory::getApplication(); $replyTo = $app->get('replyto', ''); $replyToName = $app->get('replytoname', ''); if ((int) $config->get('alternative_mailconfig', 0) === 1 && (int) $params->get('alternative_mailconfig', 0) === 1) { if ($this->mailer->Mailer === 'smtp' || $params->get('mailer') === 'smtp') { $smtpauth = ($params->get('smtpauth', $app->get('smtpauth')) == 0) ? null : 1; $smtpuser = $params->get('smtpuser', $app->get('smtpuser')); $smtppass = $params->get('smtppass', $app->get('smtppass')); $smtphost = $params->get('smtphost', $app->get('smtphost')); $smtpsecure = $params->get('smtpsecure', $app->get('smtpsecure')); $smtpport = $params->get('smtpport', $app->get('smtpport')); $this->mailer->useSmtp($smtpauth, $smtphost, $smtpuser, $smtppass, $smtpsecure, $smtpport); } if ($params->get('mailer') === 'sendmail') { $this->mailer->isSendmail(); } $mailfrom = $params->get('mailfrom', $app->get('mailfrom')); $fromname = $params->get('fromname', $app->get('fromname')); if (MailHelper::isEmailAddress($mailfrom)) { $this->mailer->setFrom(MailHelper::cleanLine($mailfrom), MailHelper::cleanLine($fromname), false); } $replyTo = $params->get('replyto', $replyTo); $replyToName = $params->get('replytoname', $replyToName); } $app->triggerEvent('onMailBeforeRendering', [$this->template_id, &$this]); $subject = $this->replaceTags(Text::_($mail->subject), $this->data); $this->mailer->setSubject($subject); $mailStyle = $config->get('mail_style', 'plaintext'); $plainBody = $this->replaceTags(Text::_($mail->body), $this->data); $htmlBody = $this->replaceTags(Text::_($mail->htmlbody), $this->data, true); if ($mailStyle === 'plaintext' || $mailStyle === 'both') { // If the Plain template is empty try to convert the HTML template to a Plain text if (!$plainBody) { $plainBody = strip_tags(str_replace(['<br>', '<br />', '<br/>'], "\n", $htmlBody)); } $this->mailer->setBody($plainBody); // Set alt body, use $mailer->Body directly because it was filtered by $mailer->setBody() if ($mailStyle === 'both') { $this->mailer->AltBody = $this->mailer->Body; } } if ($mailStyle === 'html' || $mailStyle === 'both') { $this->mailer->isHtml(true); // If HTML body is empty try to convert the Plain template to html if (!$htmlBody) { $htmlBody = nl2br($this->replaceTags(Text::_($mail->body), $this->data, true), false); } $htmlBody = MailHelper::convertRelativeToAbsoluteUrls($htmlBody); $this->mailer->setBody($htmlBody); } if ($config->get('copy_mails') && $params->get('copyto')) { $this->mailer->addBcc($params->get('copyto')); } foreach ($this->recipients as $recipient) { switch ($recipient->type) { case 'cc': $this->mailer->addCc($recipient->mail, $recipient->name); break; case 'bcc': $this->mailer->addBcc($recipient->mail, $recipient->name); break; case 'to': default: $this->mailer->addAddress($recipient->mail, $recipient->name); } } if ($this->replyto) { $this->mailer->addReplyTo($this->replyto->mail, $this->replyto->name); } elseif ($replyTo) { $this->mailer->addReplyTo($replyTo, $replyToName); } if (trim($config->get('attachment_folder', ''))) { $folderPath = rtrim(Path::check(JPATH_ROOT . '/' . $config->get('attachment_folder')), \DIRECTORY_SEPARATOR); if ($folderPath && $folderPath !== Path::clean(JPATH_ROOT) && is_dir($folderPath)) { foreach ((array) json_decode($mail->attachments) as $attachment) { $filePath = Path::check($folderPath . '/' . $attachment->file); if (is_file($filePath)) { $this->mailer->addAttachment($filePath, $this->getAttachmentName($filePath, $attachment->name)); } } } } foreach ($this->attachments as $attachment) { if (is_file($attachment->file)) { $this->mailer->addAttachment($attachment->file, $this->getAttachmentName($attachment->file, $attachment->name)); } else { $this->mailer->addStringAttachment($attachment->file, $attachment->name); } } return $this->mailer->Send(); } /** * Replace tags with their values recursively * * @param string $text The template to process * @param array $tags An associative array to replace in the template * @param bool $isHtml Is the text an HTML text and requires escaping * * @return string Rendered mail template * * @since 4.0.0 */ protected function replaceTags($text, $tags, $isHtml = false) { foreach ($tags as $key => $value) { // If the value is NULL, replace with an empty string. NULL itself throws notices if (\is_null($value)) { $value = ''; } if (\is_array($value)) { $matches = []; $pregKey = preg_quote(strtoupper($key), '/'); if (preg_match_all('/{' . $pregKey . '}(.*?){\/' . $pregKey . '}/s', $text, $matches)) { foreach ($matches[0] as $i => $match) { $replacement = ''; foreach ($value as $name => $subvalue) { if (\is_array($subvalue) && $name == $matches[1][$i]) { $subvalue = implode("\n", $subvalue); // Escape if necessary if ($isHtml && \in_array(strtoupper($key), $this->unsafe_tags, true)) { $subvalue = htmlspecialchars($subvalue, ENT_QUOTES, 'UTF-8'); } $replacement .= implode("\n", $subvalue); } elseif (\is_array($subvalue)) { $replacement .= $this->replaceTags($matches[1][$i], $subvalue, $isHtml); } elseif (\is_string($subvalue) && $name == $matches[1][$i]) { // Escape if necessary if ($isHtml && \in_array(strtoupper($key), $this->unsafe_tags, true)) { $subvalue = htmlspecialchars($subvalue, ENT_QUOTES, 'UTF-8'); } $replacement .= $subvalue; } } $text = str_replace($match, $replacement, $text); } } } else { // Escape if necessary if ($isHtml && \in_array(strtoupper($key), $this->unsafe_tags, true)) { $value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); } $text = str_replace('{' . strtoupper($key) . '}', $value, $text); } } return $text; } /** * Get a specific mail template * * @param string $key Template identifier * @param string $language Language code of the template * * @return object|null An object with the data of the mail, or null if the template not found in the db. * * @since 4.0.0 */ public static function getTemplate($key, $language) { $db = Factory::getDbo(); $query = $db->getQuery(true); $query->select('*') ->from($db->quoteName('#__mail_templates')) ->where($db->quoteName('template_id') . ' = :key') ->whereIn($db->quoteName('language'), ['', $language], ParameterType::STRING) ->order($db->quoteName('language') . ' DESC') ->bind(':key', $key); $db->setQuery($query); $mail = $db->loadObject(); if ($mail) { $mail->params = new Registry($mail->params); } return $mail; } /** * Insert a new mail template into the system * * @param string $key Mail template key * @param string $subject A default subject (normally a translatable string) * @param string $body A default body (normally a translatable string) * @param array $tags Associative array of tags to replace * @param string $htmlbody A default htmlbody (normally a translatable string) * * @return boolean True on success, false on failure * * @since 4.0.0 */ public static function createTemplate($key, $subject, $body, $tags, $htmlbody = '') { $db = Factory::getDbo(); $template = new \stdClass(); $template->template_id = $key; $template->language = ''; $template->subject = $subject; $template->body = $body; $template->htmlbody = $htmlbody; $template->extension = explode('.', $key, 2)[0] ?? ''; $template->attachments = ''; $params = new \stdClass(); $params->tags = (array) $tags; $template->params = json_encode($params); return $db->insertObject('#__mail_templates', $template); } /** * Update an existing mail template * * @param string $key Mail template key * @param string $subject A default subject (normally a translatable string) * @param string $body A default body (normally a translatable string) * @param array $tags Associative array of tags to replace * @param string $htmlbody A default htmlbody (normally a translatable string) * * @return boolean True on success, false on failure * * @since 4.0.0 */ public static function updateTemplate($key, $subject, $body, $tags, $htmlbody = '') { $db = Factory::getDbo(); $template = new \stdClass(); $template->template_id = $key; $template->language = ''; $template->subject = $subject; $template->body = $body; $template->htmlbody = $htmlbody; $params = new \stdClass(); $params->tags = (array) $tags; $template->params = json_encode($params); return $db->updateObject('#__mail_templates', $template, ['template_id', 'language']); } /** * Method to delete a mail template * * @param string $key The key of the mail template * * @return boolean True on success, false on failure * * @since 4.0.0 */ public static function deleteTemplate($key) { $db = Factory::getDbo(); $query = $db->getQuery(true); $query->delete($db->quoteName('#__mail_templates')) ->where($db->quoteName('template_id') . ' = :key') ->bind(':key', $key); $db->setQuery($query); return $db->execute(); } /** * Check and if necessary fix the file name of an attachment so that the attached file * has the same extension as the source file, and not a different file extension * * @param string $file Path to the file to be attached * @param string $name The file name to be used for the attachment * * @return string The corrected file name for the attachment * * @since 4.0.0 */ protected function getAttachmentName(string $file, string $name): string { // If no name is given, do not process it further if (!trim($name)) { return ''; } // Replace any placeholders. $name = $this->replaceTags($name, $this->data); // Get the file extension. $ext = File::getExt($file); // Strip off extension from $name and append extension of $file, if any return File::stripExt($name) . ($ext ? '.' . $ext : ''); } } MailerFactoryAwareTrait.php 0000644 00000002637 15172602777 0012030 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Mail; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Defines the trait for a MailerFactoryInterface aware class. * * @since 4.4.0 */ trait MailerFactoryAwareTrait { /** * MailerFactoryInterface * * @var MailerFactoryInterface * @since 4.4.0 */ private $mailerFactory; /** * Get the MailerFactoryInterface. * * @return MailerFactoryInterface * * @since 4.4.0 * @throws \UnexpectedValueException May be thrown if the MailerFactory has not been set. */ protected function getMailerFactory(): MailerFactoryInterface { if ($this->mailerFactory) { return $this->mailerFactory; } throw new \UnexpectedValueException('MailerFactory not set in ' . __CLASS__); } /** * Set the mailer factory to use. * * @param ?MailerFactoryInterface $mailerFactory The mailer factory to use. * * @return void * * @since 4.4.0 */ public function setMailerFactory(?MailerFactoryInterface $mailerFactory = null): void { $this->mailerFactory = $mailerFactory; } }
| ver. 1.4 |
Github
|
.
| PHP 8.3.23 | Generation time: 0 |
proxy
|
phpinfo
|
Settings