[ Index ]

MailPress 544

[ Index ]     [ Classes ]     [ Functions ]     [ Variables ]     [ Constants ]     [ Statistics ]    

title

Body

[close]

/mp-includes/Swiftmailer/classes/Swift/Transport/ -> AbstractSmtpTransport.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of SwiftMailer.
   5   * (c) 2004-2009 Chris Corbyn
   6   *
   7   * For the full copyright and license information, please view the LICENSE
   8   * file that was distributed with this source code.
   9   */
  10  
  11  /**
  12   * Sends Messages over SMTP.
  13   *
  14   * @author Chris Corbyn
  15   */
  16  abstract class Swift_Transport_AbstractSmtpTransport implements Swift_Transport
  17  {
  18      /** Input-Output buffer for sending/receiving SMTP commands and responses */
  19      protected $_buffer;
  20  
  21      /** Connection status */
  22      protected $_started = false;
  23  
  24      /** The domain name to use in HELO command */
  25      protected $_domain = '[127.0.0.1]';
  26  
  27      /** The event dispatching layer */
  28      protected $_eventDispatcher;
  29  
  30      /** Source Ip */
  31      protected $_sourceIp;
  32  
  33      /** Return an array of params for the Buffer */
  34      abstract protected function _getBufferParams();
  35  
  36      /**
  37       * Creates a new EsmtpTransport using the given I/O buffer.
  38       *
  39       * @param Swift_Transport_IoBuffer     $buf
  40       * @param Swift_Events_EventDispatcher $dispatcher
  41       */
  42      public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher)
  43      {
  44          $this->_eventDispatcher = $dispatcher;
  45          $this->_buffer = $buf;
  46          $this->_lookupHostname();
  47      }
  48  
  49      /**
  50       * Set the name of the local domain which Swift will identify itself as.
  51       *
  52       * This should be a fully-qualified domain name and should be truly the domain
  53       * you're using.
  54       *
  55       * If your server doesn't have a domain name, use the IP in square
  56       * brackets (i.e. [127.0.0.1]).
  57       *
  58       * @param string $domain
  59       *
  60       * @return Swift_Transport_AbstractSmtpTransport
  61       */
  62      public function setLocalDomain($domain)
  63      {
  64          $this->_domain = $domain;
  65  
  66          return $this;
  67      }
  68  
  69      /**
  70       * Get the name of the domain Swift will identify as.
  71       *
  72       * @return string
  73       */
  74      public function getLocalDomain()
  75      {
  76          return $this->_domain;
  77      }
  78  
  79      /**
  80       * Sets the source IP.
  81       *
  82       * @param string $source
  83       */
  84      public function setSourceIp($source)
  85      {
  86          $this->_sourceIp = $source;
  87      }
  88  
  89      /**
  90       * Returns the IP used to connect to the destination.
  91       *
  92       * @return string
  93       */
  94      public function getSourceIp()
  95      {
  96          return $this->_sourceIp;
  97      }
  98  
  99      /**
 100       * Start the SMTP connection.
 101       */
 102      public function start()
 103      {
 104          if (!$this->_started) {
 105              if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) {
 106                  $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted');
 107                  if ($evt->bubbleCancelled()) {
 108                      return;
 109                  }
 110              }
 111  
 112              try {
 113                  $this->_buffer->initialize($this->_getBufferParams());
 114              } catch (Swift_TransportException $e) {
 115                  $this->_throwException($e);
 116              }
 117              $this->_readGreeting();
 118              $this->_doHeloCommand();
 119  
 120              if ($evt) {
 121                  $this->_eventDispatcher->dispatchEvent($evt, 'transportStarted');
 122              }
 123  
 124              $this->_started = true;
 125          }
 126      }
 127  
 128      /**
 129       * Test if an SMTP connection has been established.
 130       *
 131       * @return bool
 132       */
 133      public function isStarted()
 134      {
 135          return $this->_started;
 136      }
 137  
 138      /**
 139       * Send the given Message.
 140       *
 141       * Recipient/sender data will be retrieved from the Message API.
 142       * The return value is the number of recipients who were accepted for delivery.
 143       *
 144       * @param Swift_Mime_Message $message
 145       * @param string[]           $failedRecipients An array of failures by-reference
 146       *
 147       * @return int
 148       */
 149      public function send(Swift_Mime_Message $message, &$failedRecipients = null)
 150      {
 151          $sent = 0;
 152          $failedRecipients = (array) $failedRecipients;
 153  
 154          if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) {
 155              $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
 156              if ($evt->bubbleCancelled()) {
 157                  return 0;
 158              }
 159          }
 160  
 161          if (!$reversePath = $this->_getReversePath($message)) {
 162              $this->_throwException(new Swift_TransportException(
 163                  'Cannot send message without a sender address'
 164                  )
 165              );
 166          }
 167  
 168          $to = (array) $message->getTo();
 169          $cc = (array) $message->getCc();
 170          $tos = array_merge($to, $cc);
 171          $bcc = (array) $message->getBcc();
 172  
 173          $message->setBcc(array());
 174  
 175          try {
 176              $sent += $this->_sendTo($message, $reversePath, $tos, $failedRecipients);
 177              $sent += $this->_sendBcc($message, $reversePath, $bcc, $failedRecipients);
 178          } catch (Exception $e) {
 179              $message->setBcc($bcc);
 180              throw $e;
 181          }
 182  
 183          $message->setBcc($bcc);
 184  
 185          if ($evt) {
 186              if ($sent == count($to) + count($cc) + count($bcc)) {
 187                  $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
 188              } elseif ($sent > 0) {
 189                  $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE);
 190              } else {
 191                  $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED);
 192              }
 193              $evt->setFailedRecipients($failedRecipients);
 194              $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed');
 195          }
 196  
 197          $message->generateId(); //Make sure a new Message ID is used
 198  
 199          return $sent;
 200      }
 201  
 202      /**
 203       * Stop the SMTP connection.
 204       */
 205      public function stop()
 206      {
 207          if ($this->_started) {
 208              if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) {
 209                  $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped');
 210                  if ($evt->bubbleCancelled()) {
 211                      return;
 212                  }
 213              }
 214  
 215              try {
 216                  $this->executeCommand("QUIT\r\n", array(221));
 217              } catch (Swift_TransportException $e) {
 218              }
 219  
 220              try {
 221                  $this->_buffer->terminate();
 222  
 223                  if ($evt) {
 224                      $this->_eventDispatcher->dispatchEvent($evt, 'transportStopped');
 225                  }
 226              } catch (Swift_TransportException $e) {
 227                  $this->_throwException($e);
 228              }
 229          }
 230          $this->_started = false;
 231      }
 232  
 233      /**
 234       * Register a plugin.
 235       *
 236       * @param Swift_Events_EventListener $plugin
 237       */
 238      public function registerPlugin(Swift_Events_EventListener $plugin)
 239      {
 240          $this->_eventDispatcher->bindEventListener($plugin);
 241      }
 242  
 243      /**
 244       * Reset the current mail transaction.
 245       */
 246      public function reset()
 247      {
 248          $this->executeCommand("RSET\r\n", array(250));
 249      }
 250  
 251      /**
 252       * Get the IoBuffer where read/writes are occurring.
 253       *
 254       * @return Swift_Transport_IoBuffer
 255       */
 256      public function getBuffer()
 257      {
 258          return $this->_buffer;
 259      }
 260  
 261      /**
 262       * Run a command against the buffer, expecting the given response codes.
 263       *
 264       * If no response codes are given, the response will not be validated.
 265       * If codes are given, an exception will be thrown on an invalid response.
 266       *
 267       * @param string   $command
 268       * @param int[]    $codes
 269       * @param string[] $failures An array of failures by-reference
 270       *
 271       * @return string
 272       */
 273      public function executeCommand($command, $codes = array(), &$failures = null)
 274      {
 275          $failures = (array) $failures;
 276          $seq = $this->_buffer->write($command);
 277          $response = $this->_getFullResponse($seq);
 278          if ($evt = $this->_eventDispatcher->createCommandEvent($this, $command, $codes)) {
 279              $this->_eventDispatcher->dispatchEvent($evt, 'commandSent');
 280          }
 281          $this->_assertResponseCode($response, $codes);
 282  
 283          return $response;
 284      }
 285  
 286      /** Read the opening SMTP greeting */
 287      protected function _readGreeting()
 288      {
 289          $this->_assertResponseCode($this->_getFullResponse(0), array(220));
 290      }
 291  
 292      /** Send the HELO welcome */
 293      protected function _doHeloCommand()
 294      {
 295          $this->executeCommand(
 296              sprintf("HELO %s\r\n", $this->_domain), array(250)
 297              );
 298      }
 299  
 300      /** Send the MAIL FROM command */
 301      protected function _doMailFromCommand($address)
 302      {
 303          $this->executeCommand(
 304              sprintf("MAIL FROM:<%s>\r\n", $address), array(250)
 305              );
 306      }
 307  
 308      /** Send the RCPT TO command */
 309      protected function _doRcptToCommand($address)
 310      {
 311          $this->executeCommand(
 312              sprintf("RCPT TO:<%s>\r\n", $address), array(250, 251, 252)
 313              );
 314      }
 315  
 316      /** Send the DATA command */
 317      protected function _doDataCommand()
 318      {
 319          $this->executeCommand("DATA\r\n", array(354));
 320      }
 321  
 322      /** Stream the contents of the message over the buffer */
 323      protected function _streamMessage(Swift_Mime_Message $message)
 324      {
 325          $this->_buffer->setWriteTranslations(array("\r\n." => "\r\n.."));
 326          try {
 327              $message->toByteStream($this->_buffer);
 328              $this->_buffer->flushBuffers();
 329          } catch (Swift_TransportException $e) {
 330              $this->_throwException($e);
 331          }
 332          $this->_buffer->setWriteTranslations(array());
 333          $this->executeCommand("\r\n.\r\n", array(250));
 334      }
 335  
 336      /** Determine the best-use reverse path for this message */
 337      protected function _getReversePath(Swift_Mime_Message $message)
 338      {
 339          $return = $message->getReturnPath();
 340          $sender = $message->getSender();
 341          $from = $message->getFrom();
 342          $path = null;
 343          if (!empty($return)) {
 344              $path = $return;
 345          } elseif (!empty($sender)) {
 346              // Don't use array_keys
 347              reset($sender); // Reset Pointer to first pos
 348              $path = key($sender); // Get key
 349          } elseif (!empty($from)) {
 350              reset($from); // Reset Pointer to first pos
 351              $path = key($from); // Get key
 352          }
 353  
 354          return $path;
 355      }
 356  
 357      /** Throw a TransportException, first sending it to any listeners */
 358      protected function _throwException(Swift_TransportException $e)
 359      {
 360          if ($evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e)) {
 361              $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown');
 362              if (!$evt->bubbleCancelled()) {
 363                  throw $e;
 364              }
 365          } else {
 366              throw $e;
 367          }
 368      }
 369  
 370      /** Throws an Exception if a response code is incorrect */
 371      protected function _assertResponseCode($response, $wanted)
 372      {
 373          list($code) = sscanf($response, '%3d');
 374          $valid = (empty($wanted) || in_array($code, $wanted));
 375  
 376          if ($evt = $this->_eventDispatcher->createResponseEvent($this, $response,
 377              $valid)) {
 378              $this->_eventDispatcher->dispatchEvent($evt, 'responseReceived');
 379          }
 380  
 381          if (!$valid) {
 382              $this->_throwException(
 383                  new Swift_TransportException(
 384                      'Expected response code '.implode('/', $wanted).' but got code '.
 385                      '"'.$code.'", with message "'.$response.'"',
 386                      $code)
 387                  );
 388          }
 389      }
 390  
 391      /** Get an entire multi-line response using its sequence number */
 392      protected function _getFullResponse($seq)
 393      {
 394          $response = '';
 395          try {
 396              do {
 397                  $line = $this->_buffer->readLine($seq);
 398                  $response .= $line;
 399              } while (null !== $line && false !== $line && ' ' != $line{3});
 400          } catch (Swift_TransportException $e) {
 401              $this->_throwException($e);
 402          } catch (Swift_IoException $e) {
 403              $this->_throwException(
 404                  new Swift_TransportException(
 405                      $e->getMessage())
 406                  );
 407          }
 408  
 409          return $response;
 410      }
 411  
 412      /** Send an email to the given recipients from the given reverse path */
 413      private function _doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients)
 414      {
 415          $sent = 0;
 416          $this->_doMailFromCommand($reversePath);
 417          foreach ($recipients as $forwardPath) {
 418              try {
 419                  $this->_doRcptToCommand($forwardPath);
 420                  $sent++;
 421              } catch (Swift_TransportException $e) {
 422                  $failedRecipients[] = $forwardPath;
 423              }
 424          }
 425  
 426          if ($sent != 0) {
 427              $this->_doDataCommand();
 428              $this->_streamMessage($message);
 429          } else {
 430              $this->reset();
 431          }
 432  
 433          return $sent;
 434      }
 435  
 436      /** Send a message to the given To: recipients */
 437      private function _sendTo(Swift_Mime_Message $message, $reversePath, array $to, array &$failedRecipients)
 438      {
 439          if (empty($to)) {
 440              return 0;
 441          }
 442  
 443          return $this->_doMailTransaction($message, $reversePath, array_keys($to),
 444              $failedRecipients);
 445      }
 446  
 447      /** Send a message to all Bcc: recipients */
 448      private function _sendBcc(Swift_Mime_Message $message, $reversePath, array $bcc, array &$failedRecipients)
 449      {
 450          $sent = 0;
 451          foreach ($bcc as $forwardPath => $name) {
 452              $message->setBcc(array($forwardPath => $name));
 453              $sent += $this->_doMailTransaction(
 454                  $message, $reversePath, array($forwardPath), $failedRecipients
 455                  );
 456          }
 457  
 458          return $sent;
 459      }
 460  
 461      /** Try to determine the hostname of the server this is run on */
 462      private function _lookupHostname()
 463      {
 464          if (!empty($_SERVER['SERVER_NAME'])
 465              && $this->_isFqdn($_SERVER['SERVER_NAME'])) {
 466              $this->_domain = $_SERVER['SERVER_NAME'];
 467          } elseif (!empty($_SERVER['SERVER_ADDR'])) {
 468              $this->_domain = sprintf('[%s]', $_SERVER['SERVER_ADDR']);
 469          }
 470      }
 471  
 472      /** Determine is the $hostname is a fully-qualified name */
 473      private function _isFqdn($hostname)
 474      {
 475          // We could do a really thorough check, but there's really no point
 476          if (false !== $dotPos = strpos($hostname, '.')) {
 477              return ($dotPos > 0) && ($dotPos != strlen($hostname) - 1);
 478          } else {
 479              return false;
 480          }
 481      }
 482  
 483      /**
 484       * Destructor.
 485       */
 486      public function __destruct()
 487      {
 488          $this->stop();
 489      }
 490  }


Generated: Thu Apr 28 18:38:52 2016 Cross-referenced by PHPXref 0.7.1