PageRenderTime 46ms CodeModel.GetById 14ms app.highlight 21ms RepoModel.GetById 2ms app.codeStats 0ms

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

http://zoop.googlecode.com/
PHP | 413 lines | 142 code | 75 blank | 196 comment | 18 complexity | f52ae318624e48961abc62321c7448a7 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: Abstract.php 21635 2010-03-24 15:25:13Z yoshida@zend.co.jp $
 22 */
 23
 24
 25/**
 26 * @see Zend_Validate
 27 */
 28require_once 'Zend/Validate.php';
 29
 30
 31/**
 32 * @see Zend_Validate_Hostname
 33 */
 34require_once 'Zend/Validate/Hostname.php';
 35
 36
 37/**
 38 * Zend_Mail_Protocol_Abstract
 39 *
 40 * Provides low-level methods for concrete adapters to communicate with a remote mail server and track requests and responses.
 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 * @version    $Id: Abstract.php 21635 2010-03-24 15:25:13Z yoshida@zend.co.jp $
 48 * @todo Implement proxy settings
 49 */
 50abstract class Zend_Mail_Protocol_Abstract
 51{
 52    /**
 53     * Mail default EOL string
 54     */
 55    const EOL = "\r\n";
 56
 57
 58    /**
 59     * Default timeout in seconds for initiating session
 60     */
 61    const TIMEOUT_CONNECTION = 30;
 62
 63    /**
 64     * Maximum of the transaction log
 65     */
 66    const MAXIMUM_LOG = 64;
 67
 68
 69    /**
 70     * Hostname or IP address of remote server
 71     * @var string
 72     */
 73    protected $_host;
 74
 75
 76    /**
 77     * Port number of connection
 78     * @var integer
 79     */
 80    protected $_port;
 81
 82
 83    /**
 84     * Instance of Zend_Validate to check hostnames
 85     * @var Zend_Validate
 86     */
 87    protected $_validHost;
 88
 89
 90    /**
 91     * Socket connection resource
 92     * @var resource
 93     */
 94    protected $_socket;
 95
 96
 97    /**
 98     * Last request sent to server
 99     * @var string
100     */
101    protected $_request;
102
103
104    /**
105     * Array of server responses to last request
106     * @var array
107     */
108    protected $_response;
109
110
111    /**
112     * String template for parsing server responses using sscanf (default: 3 digit code and response string)
113     * @var resource
114     * @deprecated Since 1.10.3
115     */
116    protected $_template = '%d%s';
117
118
119    /**
120     * Log of mail requests and server responses for a session
121     * @var array
122     */
123    private $_log = array();
124
125
126    /**
127     * Constructor.
128     *
129     * @param  string  $host OPTIONAL Hostname of remote connection (default: 127.0.0.1)
130     * @param  integer $port OPTIONAL Port number (default: null)
131     * @throws Zend_Mail_Protocol_Exception
132     * @return void
133     */
134    public function __construct($host = '127.0.0.1', $port = null)
135    {
136        $this->_validHost = new Zend_Validate();
137        $this->_validHost->addValidator(new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL));
138
139        if (!$this->_validHost->isValid($host)) {
140            /**
141             * @see Zend_Mail_Protocol_Exception
142             */
143            require_once 'Zend/Mail/Protocol/Exception.php';
144            throw new Zend_Mail_Protocol_Exception(join(', ', $this->_validHost->getMessages()));
145        }
146
147        $this->_host = $host;
148        $this->_port = $port;
149    }
150
151
152    /**
153     * Class destructor to cleanup open resources
154     *
155     * @return void
156     */
157    public function __destruct()
158    {
159        $this->_disconnect();
160    }
161
162
163    /**
164     * Create a connection to the remote host
165     *
166     * Concrete adapters for this class will implement their own unique connect scripts, using the _connect() method to create the socket resource.
167     */
168    abstract public function connect();
169
170
171    /**
172     * Retrieve the last client request
173     *
174     * @return string
175     */
176    public function getRequest()
177    {
178        return $this->_request;
179    }
180
181
182    /**
183     * Retrieve the last server response
184     *
185     * @return array
186     */
187    public function getResponse()
188    {
189        return $this->_response;
190    }
191
192
193    /**
194     * Retrieve the transaction log
195     *
196     * @return string
197     */
198    public function getLog()
199    {
200        return implode('', $this->_log);
201    }
202
203
204    /**
205     * Reset the transaction log
206     *
207     * @return void
208     */
209    public function resetLog()
210    {
211        $this->_log = array();
212    }
213
214    /**
215     * Add the transaction log
216     *
217     * @param  string new transaction
218     * @return void
219     */
220    protected function _addLog($value)
221    {
222        if (count($this->_log) >= self::MAXIMUM_LOG) {
223            array_shift($this->_log);
224        }
225
226        $this->_log[] = $value;
227    }
228
229    /**
230     * Connect to the server using the supplied transport and target
231     *
232     * An example $remote string may be 'tcp://mail.example.com:25' or 'ssh://hostname.com:2222'
233     *
234     * @param  string $remote Remote
235     * @throws Zend_Mail_Protocol_Exception
236     * @return boolean
237     */
238    protected function _connect($remote)
239    {
240        $errorNum = 0;
241        $errorStr = '';
242
243        // open connection
244        $this->_socket = @stream_socket_client($remote, $errorNum, $errorStr, self::TIMEOUT_CONNECTION);
245
246        if ($this->_socket === false) {
247            if ($errorNum == 0) {
248                $errorStr = 'Could not open socket';
249            }
250            /**
251             * @see Zend_Mail_Protocol_Exception
252             */
253            require_once 'Zend/Mail/Protocol/Exception.php';
254            throw new Zend_Mail_Protocol_Exception($errorStr);
255        }
256
257        if (($result = stream_set_timeout($this->_socket, self::TIMEOUT_CONNECTION)) === false) {
258            /**
259             * @see Zend_Mail_Protocol_Exception
260             */
261            require_once 'Zend/Mail/Protocol/Exception.php';
262            throw new Zend_Mail_Protocol_Exception('Could not set stream timeout');
263        }
264
265        return $result;
266    }
267
268
269    /**
270     * Disconnect from remote host and free resource
271     *
272     * @return void
273     */
274    protected function _disconnect()
275    {
276        if (is_resource($this->_socket)) {
277            fclose($this->_socket);
278        }
279    }
280
281
282    /**
283     * Send the given request followed by a LINEEND to the server.
284     *
285     * @param  string $request
286     * @throws Zend_Mail_Protocol_Exception
287     * @return integer|boolean Number of bytes written to remote host
288     */
289    protected function _send($request)
290    {
291        if (!is_resource($this->_socket)) {
292            /**
293             * @see Zend_Mail_Protocol_Exception
294             */
295            require_once 'Zend/Mail/Protocol/Exception.php';
296            throw new Zend_Mail_Protocol_Exception('No connection has been established to ' . $this->_host);
297        }
298
299        $this->_request = $request;
300
301        $result = fwrite($this->_socket, $request . self::EOL);
302
303        // Save request to internal log
304        $this->_addLog($request . self::EOL);
305
306        if ($result === false) {
307            /**
308             * @see Zend_Mail_Protocol_Exception
309             */
310            require_once 'Zend/Mail/Protocol/Exception.php';
311            throw new Zend_Mail_Protocol_Exception('Could not send request to ' . $this->_host);
312        }
313
314        return $result;
315    }
316
317
318    /**
319     * Get a line from the stream.
320     *
321     * @var    integer $timeout Per-request timeout value if applicable
322     * @throws Zend_Mail_Protocol_Exception
323     * @return string
324     */
325    protected function _receive($timeout = null)
326    {
327        if (!is_resource($this->_socket)) {
328            /**
329             * @see Zend_Mail_Protocol_Exception
330             */
331            require_once 'Zend/Mail/Protocol/Exception.php';
332            throw new Zend_Mail_Protocol_Exception('No connection has been established to ' . $this->_host);
333        }
334
335        // Adapters may wish to supply per-commend timeouts according to appropriate RFC
336        if ($timeout !== null) {
337           stream_set_timeout($this->_socket, $timeout);
338        }
339
340        // Retrieve response
341        $reponse = fgets($this->_socket, 1024);
342
343        // Save request to internal log
344        $this->_addLog($reponse);
345
346        // Check meta data to ensure connection is still valid
347        $info = stream_get_meta_data($this->_socket);
348
349        if (!empty($info['timed_out'])) {
350            /**
351             * @see Zend_Mail_Protocol_Exception
352             */
353            require_once 'Zend/Mail/Protocol/Exception.php';
354            throw new Zend_Mail_Protocol_Exception($this->_host . ' has timed out');
355        }
356
357        if ($reponse === false) {
358            /**
359             * @see Zend_Mail_Protocol_Exception
360             */
361            require_once 'Zend/Mail/Protocol/Exception.php';
362            throw new Zend_Mail_Protocol_Exception('Could not read from ' . $this->_host);
363        }
364
365        return $reponse;
366    }
367
368
369    /**
370     * Parse server response for successful codes
371     *
372     * Read the response from the stream and check for expected return code.
373     * Throws a Zend_Mail_Protocol_Exception if an unexpected code is returned.
374     *
375     * @param  string|array $code One or more codes that indicate a successful response
376     * @throws Zend_Mail_Protocol_Exception
377     * @return string Last line of response string
378     */
379    protected function _expect($code, $timeout = null)
380    {
381        $this->_response = array();
382        $cmd  = '';
383        $more = '';
384        $msg  = '';
385        $errMsg = '';
386
387        if (!is_array($code)) {
388            $code = array($code);
389        }
390
391        do {
392            $this->_response[] = $result = $this->_receive($timeout);
393            list($cmd, $more, $msg) = preg_split('/([\s-]+)/', $result, 2, PREG_SPLIT_DELIM_CAPTURE);
394
395            if ($errMsg !== '') {
396                $errMsg .= ' ' . $msg;
397            } elseif ($cmd === null || !in_array($cmd, $code)) {
398                $errMsg =  $msg;
399            }
400
401        } while (strpos($more, '-') === 0); // The '-' message prefix indicates an information string instead of a response string.
402
403        if ($errMsg !== '') {
404            /**
405             * @see Zend_Mail_Protocol_Exception
406             */
407            require_once 'Zend/Mail/Protocol/Exception.php';
408            throw new Zend_Mail_Protocol_Exception($errMsg);
409        }
410
411        return $msg;
412    }
413}