vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php line 332

  1. <?php
  2. /*
  3.  * This file is part of SwiftMailer.
  4.  * (c) 2004-2009 Chris Corbyn
  5.  *
  6.  * For the full copyright and license information, please view the LICENSE
  7.  * file that was distributed with this source code.
  8.  */
  9. /**
  10.  * Sends Messages over SMTP with ESMTP support.
  11.  *
  12.  * @author Chris Corbyn
  13.  */
  14. class Swift_Transport_EsmtpTransport extends Swift_Transport_AbstractSmtpTransport implements Swift_Transport_SmtpAgent
  15. {
  16.     /**
  17.      * ESMTP extension handlers.
  18.      *
  19.      * @var Swift_Transport_EsmtpHandler[]
  20.      */
  21.     private $_handlers = array();
  22.     /**
  23.      * ESMTP capabilities.
  24.      *
  25.      * @var string[]
  26.      */
  27.     private $_capabilities = array();
  28.     /**
  29.      * Connection buffer parameters.
  30.      *
  31.      * @var array
  32.      */
  33.     private $_params = array(
  34.         'protocol' => 'tcp',
  35.         'host' => 'localhost',
  36.         'port' => 25,
  37.         'timeout' => 30,
  38.         'blocking' => 1,
  39.         'tls' => false,
  40.         'type' => Swift_Transport_IoBuffer::TYPE_SOCKET,
  41.         'stream_context_options' => array(),
  42.         );
  43.     /**
  44.      * Creates a new EsmtpTransport using the given I/O buffer.
  45.      *
  46.      * @param Swift_Transport_IoBuffer       $buf
  47.      * @param Swift_Transport_EsmtpHandler[] $extensionHandlers
  48.      * @param Swift_Events_EventDispatcher   $dispatcher
  49.      */
  50.     public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlersSwift_Events_EventDispatcher $dispatcher)
  51.     {
  52.         parent::__construct($buf$dispatcher);
  53.         $this->setExtensionHandlers($extensionHandlers);
  54.     }
  55.     /**
  56.      * Set the host to connect to.
  57.      *
  58.      * @param string $host
  59.      *
  60.      * @return $this
  61.      */
  62.     public function setHost($host)
  63.     {
  64.         $this->_params['host'] = $host;
  65.         return $this;
  66.     }
  67.     /**
  68.      * Get the host to connect to.
  69.      *
  70.      * @return string
  71.      */
  72.     public function getHost()
  73.     {
  74.         return $this->_params['host'];
  75.     }
  76.     /**
  77.      * Set the port to connect to.
  78.      *
  79.      * @param int $port
  80.      *
  81.      * @return $this
  82.      */
  83.     public function setPort($port)
  84.     {
  85.         $this->_params['port'] = (int) $port;
  86.         return $this;
  87.     }
  88.     /**
  89.      * Get the port to connect to.
  90.      *
  91.      * @return int
  92.      */
  93.     public function getPort()
  94.     {
  95.         return $this->_params['port'];
  96.     }
  97.     /**
  98.      * Set the connection timeout.
  99.      *
  100.      * @param int $timeout seconds
  101.      *
  102.      * @return $this
  103.      */
  104.     public function setTimeout($timeout)
  105.     {
  106.         $this->_params['timeout'] = (int) $timeout;
  107.         $this->_buffer->setParam('timeout', (int) $timeout);
  108.         return $this;
  109.     }
  110.     /**
  111.      * Get the connection timeout.
  112.      *
  113.      * @return int
  114.      */
  115.     public function getTimeout()
  116.     {
  117.         return $this->_params['timeout'];
  118.     }
  119.     /**
  120.      * Set the encryption type (tls or ssl).
  121.      *
  122.      * @param string $encryption
  123.      *
  124.      * @return $this
  125.      */
  126.     public function setEncryption($encryption)
  127.     {
  128.         $encryption strtolower($encryption);
  129.         if ('tls' == $encryption) {
  130.             $this->_params['protocol'] = 'tcp';
  131.             $this->_params['tls'] = true;
  132.         } else {
  133.             $this->_params['protocol'] = $encryption;
  134.             $this->_params['tls'] = false;
  135.         }
  136.         return $this;
  137.     }
  138.     /**
  139.      * Get the encryption type.
  140.      *
  141.      * @return string
  142.      */
  143.     public function getEncryption()
  144.     {
  145.         return $this->_params['tls'] ? 'tls' $this->_params['protocol'];
  146.     }
  147.     /**
  148.      * Sets the stream context options.
  149.      *
  150.      * @param array $options
  151.      *
  152.      * @return $this
  153.      */
  154.     public function setStreamOptions($options)
  155.     {
  156.         $this->_params['stream_context_options'] = $options;
  157.         return $this;
  158.     }
  159.     /**
  160.      * Returns the stream context options.
  161.      *
  162.      * @return array
  163.      */
  164.     public function getStreamOptions()
  165.     {
  166.         return $this->_params['stream_context_options'];
  167.     }
  168.     /**
  169.      * Sets the source IP.
  170.      *
  171.      * @param string $source
  172.      *
  173.      * @return $this
  174.      */
  175.     public function setSourceIp($source)
  176.     {
  177.         $this->_params['sourceIp'] = $source;
  178.         return $this;
  179.     }
  180.     /**
  181.      * Returns the IP used to connect to the destination.
  182.      *
  183.      * @return string
  184.      */
  185.     public function getSourceIp()
  186.     {
  187.         return isset($this->_params['sourceIp']) ? $this->_params['sourceIp'] : null;
  188.     }
  189.     /**
  190.      * Set ESMTP extension handlers.
  191.      *
  192.      * @param Swift_Transport_EsmtpHandler[] $handlers
  193.      *
  194.      * @return $this
  195.      */
  196.     public function setExtensionHandlers(array $handlers)
  197.     {
  198.         $assoc = array();
  199.         foreach ($handlers as $handler) {
  200.             $assoc[$handler->getHandledKeyword()] = $handler;
  201.         }
  202.         @uasort($assoc, array($this'_sortHandlers'));
  203.         $this->_handlers $assoc;
  204.         $this->_setHandlerParams();
  205.         return $this;
  206.     }
  207.     /**
  208.      * Get ESMTP extension handlers.
  209.      *
  210.      * @return Swift_Transport_EsmtpHandler[]
  211.      */
  212.     public function getExtensionHandlers()
  213.     {
  214.         return array_values($this->_handlers);
  215.     }
  216.     /**
  217.      * Run a command against the buffer, expecting the given response codes.
  218.      *
  219.      * If no response codes are given, the response will not be validated.
  220.      * If codes are given, an exception will be thrown on an invalid response.
  221.      *
  222.      * @param string   $command
  223.      * @param int[]    $codes
  224.      * @param string[] $failures An array of failures by-reference
  225.      *
  226.      * @return string
  227.      */
  228.     public function executeCommand($command$codes = array(), &$failures null)
  229.     {
  230.         $failures = (array) $failures;
  231.         $stopSignal false;
  232.         $response null;
  233.         foreach ($this->_getActiveHandlers() as $handler) {
  234.             $response $handler->onCommand(
  235.                 $this$command$codes$failures$stopSignal
  236.                 );
  237.             if ($stopSignal) {
  238.                 return $response;
  239.             }
  240.         }
  241.         return parent::executeCommand($command$codes$failures);
  242.     }
  243.     /** Mixin handling method for ESMTP handlers */
  244.     public function __call($method$args)
  245.     {
  246.         foreach ($this->_handlers as $handler) {
  247.             if (in_array(strtolower($method),
  248.                 array_map('strtolower', (array) $handler->exposeMixinMethods())
  249.                 )) {
  250.                 $return call_user_func_array(array($handler$method), $args);
  251.                 // Allow fluid method calls
  252.                 if (null === $return && substr($method03) == 'set') {
  253.                     return $this;
  254.                 } else {
  255.                     return $return;
  256.                 }
  257.             }
  258.         }
  259.         trigger_error('Call to undefined method '.$methodE_USER_ERROR);
  260.     }
  261.     /** Get the params to initialize the buffer */
  262.     protected function _getBufferParams()
  263.     {
  264.         return $this->_params;
  265.     }
  266.     /** Overridden to perform EHLO instead */
  267.     protected function _doHeloCommand()
  268.     {
  269.         try {
  270.             $response $this->executeCommand(
  271.                 sprintf("EHLO %s\r\n"$this->_domain), array(250)
  272.                 );
  273.         } catch (Swift_TransportException $e) {
  274.             return parent::_doHeloCommand();
  275.         }
  276.         if ($this->_params['tls']) {
  277.             try {
  278.                 $this->executeCommand("STARTTLS\r\n", array(220));
  279.                 if (!$this->_buffer->startTLS()) {
  280.                     throw new Swift_TransportException('Unable to connect with TLS encryption');
  281.                 }
  282.                 try {
  283.                     $response $this->executeCommand(
  284.                         sprintf("EHLO %s\r\n"$this->_domain), array(250)
  285.                         );
  286.                 } catch (Swift_TransportException $e) {
  287.                     return parent::_doHeloCommand();
  288.                 }
  289.             } catch (Swift_TransportException $e) {
  290.                 $this->_throwException($e);
  291.             }
  292.         }
  293.         $this->_capabilities $this->_getCapabilities($response);
  294.         $this->_setHandlerParams();
  295.         foreach ($this->_getActiveHandlers() as $handler) {
  296.             $handler->afterEhlo($this);
  297.         }
  298.     }
  299.     /** Overridden to add Extension support */
  300.     protected function _doMailFromCommand($address)
  301.     {
  302.         $handlers $this->_getActiveHandlers();
  303.         $params = array();
  304.         foreach ($handlers as $handler) {
  305.             $params array_merge($params, (array) $handler->getMailParams());
  306.         }
  307.         $paramStr = !empty($params) ? ' '.implode(' '$params) : '';
  308.         $this->executeCommand(
  309.             sprintf("MAIL FROM:<%s>%s\r\n"$address$paramStr), array(250)
  310.             );
  311.     }
  312.     /** Overridden to add Extension support */
  313.     protected function _doRcptToCommand($address)
  314.     {
  315.         $handlers $this->_getActiveHandlers();
  316.         $params = array();
  317.         foreach ($handlers as $handler) {
  318.             $params array_merge($params, (array) $handler->getRcptParams());
  319.         }
  320.         $paramStr = !empty($params) ? ' '.implode(' '$params) : '';
  321.         $this->executeCommand(
  322.             sprintf("RCPT TO:<%s>%s\r\n"$address$paramStr), array(250251252)
  323.             );
  324.     }
  325.     /** Determine ESMTP capabilities by function group */
  326.     private function _getCapabilities($ehloResponse)
  327.     {
  328.         $capabilities = array();
  329.         $ehloResponse trim($ehloResponse);
  330.         $lines explode("\r\n"$ehloResponse);
  331.         array_shift($lines);
  332.         foreach ($lines as $line) {
  333.             if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di'$line$matches)) {
  334.                 $keyword strtoupper($matches[1]);
  335.                 $paramStr strtoupper(ltrim($matches[2], ' ='));
  336.                 $params = !empty($paramStr) ? explode(' '$paramStr) : array();
  337.                 $capabilities[$keyword] = $params;
  338.             }
  339.         }
  340.         return $capabilities;
  341.     }
  342.     /** Set parameters which are used by each extension handler */
  343.     private function _setHandlerParams()
  344.     {
  345.         foreach ($this->_handlers as $keyword => $handler) {
  346.             if (array_key_exists($keyword$this->_capabilities)) {
  347.                 $handler->setKeywordParams($this->_capabilities[$keyword]);
  348.             }
  349.         }
  350.     }
  351.     /** Get ESMTP handlers which are currently ok to use */
  352.     private function _getActiveHandlers()
  353.     {
  354.         $handlers = array();
  355.         foreach ($this->_handlers as $keyword => $handler) {
  356.             if (array_key_exists($keyword$this->_capabilities)) {
  357.                 $handlers[] = $handler;
  358.             }
  359.         }
  360.         return $handlers;
  361.     }
  362.     /** Custom sort for extension handler ordering */
  363.     private function _sortHandlers($a$b)
  364.     {
  365.         return $a->getPriorityOver($b->getHandledKeyword());
  366.     }
  367. }