[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/horde/framework/Horde/Mail/Transport/ -> Smtp.php (source)

   1  <?php
   2  /**
   3   * Copyright 2010-2014 Horde LLC (http://www.horde.org/)
   4   * All rights reserved.
   5   *
   6   * Redistribution and use in source and binary forms, with or without
   7   * modification, are permitted provided that the following conditions
   8   * are met:
   9   *
  10   * o Redistributions of source code must retain the above copyright
  11   *   notice, this list of conditions and the following disclaimer.
  12   * o Redistributions in binary form must reproduce the above copyright
  13   *   notice, this list of conditions and the following disclaimer in the
  14   *   documentation and/or other materials provided with the distribution.
  15   * o The names of the authors may not be used to endorse or promote
  16   *   products derived from this software without specific prior written
  17   *   permission.
  18   *
  19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30   *
  31   * @category  Horde
  32   * @copyright 2010-2014 Horde LLC
  33   * @license   http://www.horde.org/licenses/bsd New BSD License
  34   * @package   Mail
  35   */
  36  
  37  /**
  38   * SMTP implementation.
  39   *
  40   * @author    Chuck Hagenbuch <chuck@horde.org>
  41   * @author    Jon Parise <jon@php.net>
  42   * @author    Michael Slusarz <slusarz@horde.org>
  43   * @category  Horde
  44   * @copyright 2010-2014 Horde LLC
  45   * @license   http://www.horde.org/licenses/bsd New BSD License
  46   * @package   Mail
  47   */
  48  class Horde_Mail_Transport_Smtp extends Horde_Mail_Transport
  49  {
  50      /* Error: Failed to create a Net_SMTP object */
  51      const ERROR_CREATE = 10000;
  52  
  53      /* Error: Failed to connect to SMTP server */
  54      const ERROR_CONNECT = 10001;
  55  
  56      /* Error: SMTP authentication failure */
  57      const ERROR_AUTH = 10002;
  58  
  59      /* Error: No From: address has been provided */
  60      const ERROR_FROM = 10003;
  61  
  62      /* Error: Failed to set sender */
  63      const ERROR_SENDER = 10004;
  64  
  65      /* Error: Failed to add recipient */
  66      const ERROR_RECIPIENT = 10005;
  67  
  68      /* Error: Failed to send data */
  69      const ERROR_DATA = 10006;
  70  
  71      /**
  72       * The SMTP greeting.
  73       *
  74       * @var string
  75       */
  76      public $greeting = null;
  77  
  78      /**
  79       * The SMTP queued response.
  80       *
  81       * @var string
  82       */
  83      public $queuedAs = null;
  84  
  85      /**
  86       * SMTP connection object.
  87       *
  88       * @var Net_SMTP
  89       */
  90      protected $_smtp = null;
  91  
  92      /**
  93       * The list of service extension parameters to pass to the Net_SMTP
  94       * mailFrom() command.
  95       *
  96       * @var array
  97       */
  98      protected $_extparams = array();
  99  
 100      /**
 101       * Constructor.
 102       *
 103       * @param array $params  Additional parameters:
 104       *   - auth: (mixed) SMTP authentication.
 105       *           This value may be set to true, false or the name of a
 106       *           specific authentication method. If the value is set to true,
 107       *           the Net_SMTP package will attempt to use the best
 108       *           authentication method advertised by the remote SMTP server.
 109       *           DEFAULT: false.
 110       *   - debug: (boolean) Activate SMTP debug mode?
 111       *            DEFAULT: false
 112       *   - host: (string) The server to connect to.
 113       *           DEFAULT: localhost
 114       *   - localhost: (string) Hostname or domain that will be sent to the
 115       *                remote SMTP server in the HELO / EHLO message.
 116       *                DEFAULT: localhost
 117       *   - password: (string) The password to use for SMTP auth.
 118       *               DEFAULT: NONE
 119       *   - persist: (boolean) Should the SMTP connection persist?
 120       *              DEFAULT: false
 121       *   - pipelining: (boolean) Use SMTP command pipelining.
 122       *                 Use SMTP command pipelining (specified in RFC 2920) if
 123       *                 the SMTP server supports it. This speeds up delivery
 124       *                 over high-latency connections.
 125       *                 DEFAULT: false (use default value from Net_SMTP)
 126       *   - port: (integer) The port to connect to.
 127       *           DEFAULT: 25
 128       *   - timeout: (integer) The SMTP connection timeout.
 129       *              DEFAULT: NONE
 130       *   - username: (string) The username to use for SMTP auth.
 131       *               DEFAULT: NONE
 132       */
 133      public function __construct(array $params = array())
 134      {
 135          $this->_params = array_merge(array(
 136              'auth' => false,
 137              'debug' => false,
 138              'host' => 'localhost',
 139              'localhost' => 'localhost',
 140              'password' => '',
 141              'persist' => false,
 142              'pipelining' => false,
 143              'port' => 25,
 144              'timeout' => null,
 145              'username' => ''
 146          ), $params);
 147  
 148          /* Destructor implementation to ensure that we disconnect from any
 149           * potentially-alive persistent SMTP connections. */
 150          register_shutdown_function(array($this, 'disconnect'));
 151  
 152          /* SMTP requires CRLF line endings. */
 153          $this->sep = "\r\n";
 154      }
 155  
 156      /**
 157       */
 158      public function send($recipients, array $headers, $body)
 159      {
 160          /* If we don't already have an SMTP object, create one. */
 161          $this->getSMTPObject();
 162  
 163          $headers = $this->_sanitizeHeaders($headers);
 164  
 165          /* Make sure the message has a trailing newline. */
 166          if (is_resource($body)) {
 167              fseek($body, -1, SEEK_END);
 168              switch (fgetc($body)) {
 169              case "\r":
 170                  if (fgetc($body) != "\n") {
 171                      fputs($body, "\n");
 172                  }
 173                  break;
 174  
 175              default:
 176                  fputs($body, "\r\n");
 177                  break;
 178              }
 179              rewind($body);
 180          } elseif (substr($body, -2, 0) != "\r\n") {
 181              $body .= "\r\n";
 182          }
 183  
 184          try {
 185              list($from, $textHeaders) = $this->prepareHeaders($headers);
 186          } catch (Horde_Mail_Exception $e) {
 187              $this->_smtp->rset();
 188              throw $e;
 189          }
 190  
 191          try {
 192              $from = $this->_getFrom($from, $headers);
 193          } catch (Horde_Mail_Exception $e) {
 194              $this->_smtp->rset();
 195              throw new Horde_Mail_Exception('No From: address has been provided', self::ERROR_FROM);
 196          }
 197  
 198          $params = '';
 199          foreach ($this->_extparams as $key => $val) {
 200              $params .= ' ' . $key . (is_null($val) ? '' : '=' . $val);
 201          }
 202  
 203          $res = $this->_smtp->mailFrom($from, ltrim($params));
 204          if ($res instanceof PEAR_Error) {
 205              $this->_error(sprintf("Failed to set sender: %s", $from), $res, self::ERROR_SENDER);
 206          }
 207  
 208          try {
 209              $recipients = $this->parseRecipients($recipients);
 210          } catch (Horde_Mail_Exception $e) {
 211              $this->_smtp->rset();
 212              throw $e;
 213          }
 214  
 215          foreach ($recipients as $recipient) {
 216              $res = $this->_smtp->rcptTo($recipient);
 217              if ($res instanceof PEAR_Error) {
 218                  $this->_error("Failed to add recipient: $recipient", $res, self::ERROR_RECIPIENT);
 219              }
 220          }
 221  
 222          /* Send the message's headers and the body as SMTP data. Net_SMTP does
 223           * the necessary EOL conversions. */
 224          $res = $this->_smtp->data($body, $textHeaders);
 225          list(,$args) = $this->_smtp->getResponse();
 226  
 227          if (preg_match("/Ok: queued as (.*)/", $args, $queued)) {
 228              $this->queuedAs = $queued[1];
 229          }
 230  
 231          /* We need the greeting; from it we can extract the authorative name
 232           * of the mail server we've really connected to. Ideal if we're
 233           * connecting to a round-robin of relay servers and need to track
 234           * which exact one took the email */
 235          $this->greeting = $this->_smtp->getGreeting();
 236  
 237          if ($res instanceof PEAR_Error) {
 238              $this->_error('Failed to send data', $res, self::ERROR_DATA);
 239          }
 240  
 241          /* If persistent connections are disabled, destroy our SMTP object. */
 242          if (!$this->_params['persist']) {
 243              $this->disconnect();
 244          }
 245      }
 246  
 247      /**
 248       * Connect to the SMTP server by instantiating a Net_SMTP object.
 249       *
 250       * @return Net_SMTP  The SMTP object.
 251       * @throws Horde_Mail_Exception
 252       */
 253      public function getSMTPObject()
 254      {
 255          if ($this->_smtp) {
 256              return $this->_smtp;
 257          }
 258  
 259          $this->_smtp = new Net_SMTP(
 260              $this->_params['host'],
 261              $this->_params['port'],
 262              $this->_params['localhost']
 263          );
 264  
 265          /* Set pipelining. */
 266          if ($this->_params['pipelining']) {
 267              $this->_smtp->pipelining = true;
 268          }
 269  
 270          /* If we still don't have an SMTP object at this point, fail. */
 271          if (!($this->_smtp instanceof Net_SMTP)) {
 272              throw new Horde_Mail_Exception('Failed to create a Net_SMTP object', self::ERROR_CREATE);
 273          }
 274  
 275          /* Configure the SMTP connection. */
 276          if ($this->_params['debug']) {
 277              $this->_smtp->setDebug(true);
 278          }
 279  
 280          /* Attempt to connect to the configured SMTP server. */
 281          $res = $this->_smtp->connect($this->_params['timeout']);
 282          if ($res instanceof PEAR_Error) {
 283              $this->_error('Failed to connect to ' . $this->_params['host'] . ':' . $this->_params['port'], $res, self::ERROR_CONNECT);
 284          }
 285  
 286          /* Attempt to authenticate if authentication has been enabled. */
 287          if ($this->_params['auth']) {
 288              $method = is_string($this->_params['auth'])
 289                  ? $this->_params['auth']
 290                  : '';
 291  
 292              $res = $this->_smtp->auth($this->_params['username'], $this->_params['password'], $method);
 293              if ($res instanceof PEAR_Error) {
 294                  $this->_error("$method authentication failure", $res, self::ERROR_AUTH);
 295              }
 296          }
 297  
 298          return $this->_smtp;
 299      }
 300  
 301      /**
 302       * Add parameter associated with a SMTP service extension.
 303       *
 304       * @param string $keyword  Extension keyword.
 305       * @param string $value    Any value the keyword needs.
 306       */
 307      public function addServiceExtensionParameter($keyword, $value = null)
 308      {
 309          $this->_extparams[$keyword] = $value;
 310      }
 311  
 312      /**
 313       * Disconnect and destroy the current SMTP connection.
 314       *
 315       * @return boolean True if the SMTP connection no longer exists.
 316       */
 317      public function disconnect()
 318      {
 319          /* If we have an SMTP object, disconnect and destroy it. */
 320          if (is_object($this->_smtp) && $this->_smtp->disconnect()) {
 321              $this->_smtp = null;
 322          }
 323  
 324          /* We are disconnected if we no longer have an SMTP object. */
 325          return ($this->_smtp === null);
 326      }
 327  
 328      /**
 329       * Build a standardized string describing the current SMTP error.
 330       *
 331       * @param string $text       Custom string describing the error context.
 332       * @param PEAR_Error $error  PEAR_Error object.
 333       * @param integer $e_code    Error code.
 334       *
 335       * @throws Horde_Mail_Exception
 336       */
 337      protected function _error($text, $error, $e_code)
 338      {
 339          /* Split the SMTP response into a code and a response string. */
 340          list($code, $response) = $this->_smtp->getResponse();
 341  
 342          /* Abort current SMTP transaction. */
 343          $this->_smtp->rset();
 344  
 345          /* Build our standardized error string. */
 346          throw new Horde_Mail_Exception($text . ' [SMTP: ' . $error->getMessage() . " (code: $code, response: $response)]", $e_code);
 347      }
 348  
 349  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1