Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  
   3  /**
   4   * PHPMailer - PHP email creation and transport class.
   5   * PHP Version 5.5.
   6   *
   7   * @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
   8   *
   9   * @author    Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
  10   * @author    Jim Jagielski (jimjag) <jimjag@gmail.com>
  11   * @author    Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
  12   * @author    Brent R. Matzelle (original founder)
  13   * @copyright 2012 - 2023 Marcus Bointon
  14   * @copyright 2010 - 2012 Jim Jagielski
  15   * @copyright 2004 - 2009 Andy Prevost
  16   * @license   http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  17   * @note      This program is distributed in the hope that it will be useful - WITHOUT
  18   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  19   * FITNESS FOR A PARTICULAR PURPOSE.
  20   */
  21  
  22  namespace PHPMailer\PHPMailer;
  23  
  24  /**
  25   * Configure PHPMailer with DSN string.
  26   *
  27   * @see https://en.wikipedia.org/wiki/Data_source_name
  28   *
  29   * @author Oleg Voronkovich <oleg-voronkovich@yandex.ru>
  30   */
  31  class DSNConfigurator
  32  {
  33      /**
  34       * Create new PHPMailer instance configured by DSN.
  35       *
  36       * @param string $dsn        DSN
  37       * @param bool   $exceptions Should we throw external exceptions?
  38       *
  39       * @return PHPMailer
  40       */
  41      public static function mailer($dsn, $exceptions = null)
  42      {
  43          static $configurator = null;
  44  
  45          if (null === $configurator) {
  46              $configurator = new DSNConfigurator();
  47          }
  48  
  49          return $configurator->configure(new PHPMailer($exceptions), $dsn);
  50      }
  51  
  52      /**
  53       * Configure PHPMailer instance with DSN string.
  54       *
  55       * @param PHPMailer $mailer PHPMailer instance
  56       * @param string    $dsn    DSN
  57       *
  58       * @return PHPMailer
  59       */
  60      public function configure(PHPMailer $mailer, $dsn)
  61      {
  62          $config = $this->parseDSN($dsn);
  63  
  64          $this->applyConfig($mailer, $config);
  65  
  66          return $mailer;
  67      }
  68  
  69      /**
  70       * Parse DSN string.
  71       *
  72       * @param string $dsn DSN
  73       *
  74       * @throws Exception If DSN is malformed
  75       *
  76       * @return array Configuration
  77       */
  78      private function parseDSN($dsn)
  79      {
  80          $config = $this->parseUrl($dsn);
  81  
  82          if (false === $config || !isset($config['scheme']) || !isset($config['host'])) {
  83              throw new Exception(
  84                  sprintf('Malformed DSN: "%s".', $dsn)
  85              );
  86          }
  87  
  88          if (isset($config['query'])) {
  89              parse_str($config['query'], $config['query']);
  90          }
  91  
  92          return $config;
  93      }
  94  
  95      /**
  96       * Apply configuration to mailer.
  97       *
  98       * @param PHPMailer $mailer PHPMailer instance
  99       * @param array     $config Configuration
 100       *
 101       * @throws Exception If scheme is invalid
 102       */
 103      private function applyConfig(PHPMailer $mailer, $config)
 104      {
 105          switch ($config['scheme']) {
 106              case 'mail':
 107                  $mailer->isMail();
 108                  break;
 109              case 'sendmail':
 110                  $mailer->isSendmail();
 111                  break;
 112              case 'qmail':
 113                  $mailer->isQmail();
 114                  break;
 115              case 'smtp':
 116              case 'smtps':
 117                  $mailer->isSMTP();
 118                  $this->configureSMTP($mailer, $config);
 119                  break;
 120              default:
 121                  throw new Exception(
 122                      sprintf(
 123                          'Invalid scheme: "%s". Allowed values: "mail", "sendmail", "qmail", "smtp", "smtps".',
 124                          $config['scheme']
 125                      )
 126                  );
 127          }
 128  
 129          if (isset($config['query'])) {
 130              $this->configureOptions($mailer, $config['query']);
 131          }
 132      }
 133  
 134      /**
 135       * Configure SMTP.
 136       *
 137       * @param PHPMailer $mailer PHPMailer instance
 138       * @param array     $config Configuration
 139       */
 140      private function configureSMTP($mailer, $config)
 141      {
 142          $isSMTPS = 'smtps' === $config['scheme'];
 143  
 144          if ($isSMTPS) {
 145              $mailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
 146          }
 147  
 148          $mailer->Host = $config['host'];
 149  
 150          if (isset($config['port'])) {
 151              $mailer->Port = $config['port'];
 152          } elseif ($isSMTPS) {
 153              $mailer->Port = SMTP::DEFAULT_SECURE_PORT;
 154          }
 155  
 156          $mailer->SMTPAuth = isset($config['user']) || isset($config['pass']);
 157  
 158          if (isset($config['user'])) {
 159              $mailer->Username = $config['user'];
 160          }
 161  
 162          if (isset($config['pass'])) {
 163              $mailer->Password = $config['pass'];
 164          }
 165      }
 166  
 167      /**
 168       * Configure options.
 169       *
 170       * @param PHPMailer $mailer  PHPMailer instance
 171       * @param array     $options Options
 172       *
 173       * @throws Exception If option is unknown
 174       */
 175      private function configureOptions(PHPMailer $mailer, $options)
 176      {
 177          $allowedOptions = get_object_vars($mailer);
 178  
 179          unset($allowedOptions['Mailer']);
 180          unset($allowedOptions['SMTPAuth']);
 181          unset($allowedOptions['Username']);
 182          unset($allowedOptions['Password']);
 183          unset($allowedOptions['Hostname']);
 184          unset($allowedOptions['Port']);
 185          unset($allowedOptions['ErrorInfo']);
 186  
 187          $allowedOptions = \array_keys($allowedOptions);
 188  
 189          foreach ($options as $key => $value) {
 190              if (!in_array($key, $allowedOptions)) {
 191                  throw new Exception(
 192                      sprintf(
 193                          'Unknown option: "%s". Allowed values: "%s"',
 194                          $key,
 195                          implode('", "', $allowedOptions)
 196                      )
 197                  );
 198              }
 199  
 200              switch ($key) {
 201                  case 'AllowEmpty':
 202                  case 'SMTPAutoTLS':
 203                  case 'SMTPKeepAlive':
 204                  case 'SingleTo':
 205                  case 'UseSendmailOptions':
 206                  case 'do_verp':
 207                  case 'DKIM_copyHeaderFields':
 208                      $mailer->$key = (bool) $value;
 209                      break;
 210                  case 'Priority':
 211                  case 'SMTPDebug':
 212                  case 'WordWrap':
 213                      $mailer->$key = (int) $value;
 214                      break;
 215                  default:
 216                      $mailer->$key = $value;
 217                      break;
 218              }
 219          }
 220      }
 221  
 222      /**
 223       * Parse a URL.
 224       * Wrapper for the built-in parse_url function to work around a bug in PHP 5.5.
 225       *
 226       * @param string $url URL
 227       *
 228       * @return array|false
 229       */
 230      protected function parseUrl($url)
 231      {
 232          if (\PHP_VERSION_ID >= 50600 || false === strpos($url, '?')) {
 233              return parse_url($url);
 234          }
 235  
 236          $chunks = explode('?', $url);
 237          if (is_array($chunks)) {
 238              $result = parse_url($chunks[0]);
 239              if (is_array($result)) {
 240                  $result['query'] = $chunks[1];
 241              }
 242              return $result;
 243          }
 244  
 245          return false;
 246      }
 247  }