PageRenderTime 24ms CodeModel.GetById 15ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/framework/vendor/zend/Zend/Mail/Protocol/Smtp.php

http://zoop.googlecode.com/
PHP | 443 lines | 166 code | 66 blank | 211 comment | 19 complexity | ccb525c91ea87e6db5053a990141ad3c MD5 | raw file
  1<?php
  2
  3/**
  4 * Zend Framework
  5 *
  6 * LICENSE
  7 *
  8 * This source file is subject to the new BSD license that is bundled
  9 * with this package in the file LICENSE.txt.
 10 * It is also available through the world-wide-web at this URL:
 11 * http://framework.zend.com/license/new-bsd
 12 * If you did not receive a copy of the license and are unable to
 13 * obtain it through the world-wide-web, please send an email
 14 * to license@zend.com so we can send you a copy immediately.
 15 *
 16 * @category   Zend
 17 * @package    Zend_Mail
 18 * @subpackage Protocol
 19 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 20 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 21 * @version    $Id: Smtp.php 20096 2010-01-06 02:05:09Z bkarwin $
 22 */
 23
 24
 25/**
 26 * @see Zend_Mime
 27 */
 28require_once 'Zend/Mime.php';
 29
 30
 31/**
 32 * @see Zend_Mail_Protocol_Abstract
 33 */
 34require_once 'Zend/Mail/Protocol/Abstract.php';
 35
 36
 37/**
 38 * Smtp implementation of Zend_Mail_Protocol_Abstract
 39 *
 40 * Minimum implementation according to RFC2821: EHLO, MAIL FROM, RCPT TO, DATA, RSET, NOOP, QUIT
 41 *
 42 * @category   Zend
 43 * @package    Zend_Mail
 44 * @subpackage Protocol
 45 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 46 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 47 */
 48class Zend_Mail_Protocol_Smtp extends Zend_Mail_Protocol_Abstract
 49{
 50    /**
 51     * The transport method for the socket
 52     *
 53     * @var string
 54     */
 55    protected $_transport = 'tcp';
 56
 57
 58    /**
 59     * Indicates that a session is requested to be secure
 60     *
 61     * @var string
 62     */
 63    protected $_secure;
 64
 65
 66    /**
 67     * Indicates an smtp session has been started by the HELO command
 68     *
 69     * @var boolean
 70     */
 71    protected $_sess = false;
 72
 73
 74    /**
 75     * Indicates the HELO command has been issues
 76     *
 77     * @var unknown_type
 78     */
 79    protected $_helo = false;
 80
 81
 82    /**
 83     * Indicates an smtp AUTH has been issued and authenticated
 84     *
 85     * @var unknown_type
 86     */
 87    protected $_auth = false;
 88
 89
 90    /**
 91     * Indicates a MAIL command has been issued
 92     *
 93     * @var unknown_type
 94     */
 95    protected $_mail = false;
 96
 97
 98    /**
 99     * Indicates one or more RCTP commands have been issued
100     *
101     * @var unknown_type
102     */
103    protected $_rcpt = false;
104
105
106    /**
107     * Indicates that DATA has been issued and sent
108     *
109     * @var unknown_type
110     */
111    protected $_data = null;
112
113
114    /**
115     * Constructor.
116     *
117     * @param  string  $host
118     * @param  integer $port
119     * @param  array   $config
120     * @return void
121     * @throws Zend_Mail_Protocol_Exception
122     */
123    public function __construct($host = '127.0.0.1', $port = null, array $config = array())
124    {
125        if (isset($config['ssl'])) {
126            switch (strtolower($config['ssl'])) {
127                case 'tls':
128                    $this->_secure = 'tls';
129                    break;
130
131                case 'ssl':
132                    $this->_transport = 'ssl';
133                    $this->_secure = 'ssl';
134                    if ($port == null) {
135                        $port = 465;
136                    }
137                    break;
138
139                default:
140                    /**
141                     * @see Zend_Mail_Protocol_Exception
142                     */
143                    require_once 'Zend/Mail/Protocol/Exception.php';
144                    throw new Zend_Mail_Protocol_Exception($config['ssl'] . ' is unsupported SSL type');
145                    break;
146            }
147        }
148
149        // If no port has been specified then check the master PHP ini file. Defaults to 25 if the ini setting is null.
150        if ($port == null) {
151            if (($port = ini_get('smtp_port')) == '') {
152                $port = 25;
153            }
154        }
155
156        parent::__construct($host, $port);
157    }
158
159
160    /**
161     * Connect to the server with the parameters given in the constructor.
162     *
163     * @return boolean
164     */
165    public function connect()
166    {
167        return $this->_connect($this->_transport . '://' . $this->_host . ':'. $this->_port);
168    }
169
170
171    /**
172     * Initiate HELO/EHLO sequence and set flag to indicate valid smtp session
173     *
174     * @param  string $host The client hostname or IP address (default: 127.0.0.1)
175     * @throws Zend_Mail_Protocol_Exception
176     * @return void
177     */
178    public function helo($host = '127.0.0.1')
179    {
180        // Respect RFC 2821 and disallow HELO attempts if session is already initiated.
181        if ($this->_sess === true) {
182            /**
183             * @see Zend_Mail_Protocol_Exception
184             */
185            require_once 'Zend/Mail/Protocol/Exception.php';
186            throw new Zend_Mail_Protocol_Exception('Cannot issue HELO to existing session');
187        }
188
189        // Validate client hostname
190        if (!$this->_validHost->isValid($host)) {
191            /**
192             * @see Zend_Mail_Protocol_Exception
193             */
194            require_once 'Zend/Mail/Protocol/Exception.php';
195            throw new Zend_Mail_Protocol_Exception(join(', ', $this->_validHost->getMessages()));
196        }
197
198        // Initiate helo sequence
199        $this->_expect(220, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
200        $this->_ehlo($host);
201
202        // If a TLS session is required, commence negotiation
203        if ($this->_secure == 'tls') {
204            $this->_send('STARTTLS');
205            $this->_expect(220, 180);
206            if (!stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
207                /**
208                 * @see Zend_Mail_Protocol_Exception
209                 */
210                require_once 'Zend/Mail/Protocol/Exception.php';
211                throw new Zend_Mail_Protocol_Exception('Unable to connect via TLS');
212            }
213            $this->_ehlo($host);
214        }
215
216        $this->_startSession();
217        $this->auth();
218    }
219
220
221    /**
222     * Send EHLO or HELO depending on capabilities of smtp host
223     *
224     * @param  string $host The client hostname or IP address (default: 127.0.0.1)
225     * @throws Zend_Mail_Protocol_Exception
226     * @return void
227     */
228    protected function _ehlo($host)
229    {
230        // Support for older, less-compliant remote servers. Tries multiple attempts of EHLO or HELO.
231        try {
232            $this->_send('EHLO ' . $host);
233            $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
234        } catch (Zend_Mail_Protocol_Exception $e) {
235            $this->_send('HELO ' . $host);
236            $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
237        } catch (Zend_Mail_Protocol_Exception $e) {
238            throw $e;
239        }
240    }
241
242
243    /**
244     * Issues MAIL command
245     *
246     * @param  string $from Sender mailbox
247     * @throws Zend_Mail_Protocol_Exception
248     * @return void
249     */
250    public function mail($from)
251    {
252        if ($this->_sess !== true) {
253            /**
254             * @see Zend_Mail_Protocol_Exception
255             */
256            require_once 'Zend/Mail/Protocol/Exception.php';
257            throw new Zend_Mail_Protocol_Exception('A valid session has not been started');
258        }
259
260        $this->_send('MAIL FROM:<' . $from . '>');
261        $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
262
263        // Set mail to true, clear recipients and any existing data flags as per 4.1.1.2 of RFC 2821
264        $this->_mail = true;
265        $this->_rcpt = false;
266        $this->_data = false;
267    }
268
269
270    /**
271     * Issues RCPT command
272     *
273     * @param  string $to Receiver(s) mailbox
274     * @throws Zend_Mail_Protocol_Exception
275     * @return void
276     */
277    public function rcpt($to)
278    {
279        if ($this->_mail !== true) {
280            /**
281             * @see Zend_Mail_Protocol_Exception
282             */
283            require_once 'Zend/Mail/Protocol/Exception.php';
284            throw new Zend_Mail_Protocol_Exception('No sender reverse path has been supplied');
285        }
286
287        // Set rcpt to true, as per 4.1.1.3 of RFC 2821
288        $this->_send('RCPT TO:<' . $to . '>');
289        $this->_expect(array(250, 251), 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
290        $this->_rcpt = true;
291    }
292
293
294    /**
295     * Issues DATA command
296     *
297     * @param  string $data
298     * @throws Zend_Mail_Protocol_Exception
299     * @return void
300     */
301    public function data($data)
302    {
303        // Ensure recipients have been set
304        if ($this->_rcpt !== true) {
305            /**
306             * @see Zend_Mail_Protocol_Exception
307             */
308            require_once 'Zend/Mail/Protocol/Exception.php';
309            throw new Zend_Mail_Protocol_Exception('No recipient forward path has been supplied');
310        }
311
312        $this->_send('DATA');
313        $this->_expect(354, 120); // Timeout set for 2 minutes as per RFC 2821 4.5.3.2
314
315        foreach (explode(Zend_Mime::LINEEND, $data) as $line) {
316            if (strpos($line, '.') === 0) {
317                // Escape lines prefixed with a '.'
318                $line = '.' . $line;
319            }
320            $this->_send($line);
321        }
322
323        $this->_send('.');
324        $this->_expect(250, 600); // Timeout set for 10 minutes as per RFC 2821 4.5.3.2
325        $this->_data = true;
326    }
327
328
329    /**
330     * Issues the RSET command end validates answer
331     *
332     * Can be used to restore a clean smtp communication state when a transaction has been cancelled or commencing a new transaction.
333     *
334     * @return void
335     */
336    public function rset()
337    {
338        $this->_send('RSET');
339        // MS ESMTP doesn't follow RFC, see [ZF-1377]
340        $this->_expect(array(250, 220));
341
342        $this->_mail = false;
343        $this->_rcpt = false;
344        $this->_data = false;
345    }
346
347
348    /**
349     * Issues the NOOP command end validates answer
350     *
351     * Not used by Zend_Mail, could be used to keep a connection alive or check if it is still open.
352     *
353     * @return void
354     */
355    public function noop()
356    {
357        $this->_send('NOOP');
358        $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
359    }
360
361
362    /**
363     * Issues the VRFY command end validates answer
364     *
365     * Not used by Zend_Mail.
366     *
367     * @param  string $user User Name or eMail to verify
368     * @return void
369     */
370    public function vrfy($user)
371    {
372        $this->_send('VRFY ' . $user);
373        $this->_expect(array(250, 251, 252), 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
374    }
375
376
377    /**
378     * Issues the QUIT command and clears the current session
379     *
380     * @return void
381     */
382    public function quit()
383    {
384        if ($this->_sess) {
385            $this->_send('QUIT');
386            $this->_expect(221, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
387            $this->_stopSession();
388        }
389    }
390
391
392    /**
393     * Default authentication method
394     *
395     * This default method is implemented by AUTH adapters to properly authenticate to a remote host.
396     *
397     * @throws Zend_Mail_Protocol_Exception
398     * @return void
399     */
400    public function auth()
401    {
402        if ($this->_auth === true) {
403            /**
404             * @see Zend_Mail_Protocol_Exception
405             */
406            require_once 'Zend/Mail/Protocol/Exception.php';
407            throw new Zend_Mail_Protocol_Exception('Already authenticated for this session');
408        }
409    }
410
411
412    /**
413     * Closes connection
414     *
415     * @return void
416     */
417    public function disconnect()
418    {
419        $this->_disconnect();
420    }
421
422
423    /**
424     * Start mail session
425     *
426     * @return void
427     */
428    protected function _startSession()
429    {
430        $this->_sess = true;
431    }
432
433
434    /**
435     * Stop mail session
436     *
437     * @return void
438     */
439    protected function _stopSession()
440    {
441        $this->_sess = false;
442    }
443}