📄 imap.php
字号:
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to version 1.0 of the Zend Framework
* license, that is bundled with this package in the file LICENSE.txt, and
* is available through the world-wide-web at the following URL:
* http://framework.zend.com/license/new-bsd. If you did not receive
* a copy of the Zend Framework license and are unable to obtain it
* through the world-wide-web, please send a note to license@zend.com
* so we can mail you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Imap.php 8928 2008-03-20 19:41:41Z thomas $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Imap
{
/**
* socket to imap server
* @var resource|null
*/
protected $_socket;
/**
* counter for request tag
* @var int
*/
protected $_tagCount = 0;
/**
* Public constructor
*
* @param string $host hostname of IP address of IMAP server, if given connect() is called
* @param int|null $port port of IMAP server, null for default (143 or 993 for ssl)
* @param bool $ssl use ssl? 'SSL', 'TLS' or false
* @throws Zend_Mail_Protocol_Exception
*/
function __construct($host = '', $port = null, $ssl = false)
{
if ($host) {
$this->connect($host, $port, $ssl);
}
}
/**
* Public destructor
*/
public function __destruct()
{
$this->logout();
}
/**
* Open connection to POP3 server
*
* @param string $host hostname of IP address of POP3 server
* @param int|null $port of IMAP server, default is 143 (993 for ssl)
* @param string|bool $ssl use 'SSL', 'TLS' or false
* @return string welcome message
* @throws Zend_Mail_Protocol_Exception
*/
public function connect($host, $port = null, $ssl = false)
{
if ($ssl == 'SSL') {
$host = 'ssl://' . $host;
}
if ($port === null) {
$port = $ssl === 'SSL' ? 993 : 143;
}
$this->_socket = @fsockopen($host, $port);
if (!$this->_socket) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot connect to host');
}
if (!$this->_assumedNextLine('* OK')) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('host doesn\'t allow connection');
}
if ($ssl === 'TLS') {
$result = $this->requestAndResponse('STARTTLS');
$result = $result && stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
if (!$result) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot enable TLS');
}
}
}
/**
* get the next line from socket with error checking, but nothing else
*
* @return string next line
* @throws Zend_Mail_Protocol_Exception
*/
protected function _nextLine()
{
$line = @fgets($this->_socket);
if ($line === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot read - connection closed?');
}
return $line;
}
/**
* get next line and assume it starts with $start. some requests give a simple
* feedback so we can quickly check if we can go on.
*
* @param string $start the first bytes we assume to be in the next line
* @return bool line starts with $start
* @throws Zend_Mail_Protocol_Exception
*/
protected function _assumedNextLine($start)
{
$line = $this->_nextLine();
return strpos($line, $start) === 0;
}
/**
* get next line and split the tag. that's the normal case for a response line
*
* @param string $tag tag of line is returned by reference
* @return string next line
* @throws Zend_Mail_Protocol_Exception
*/
protected function _nextTaggedLine(&$tag)
{
$line = $this->_nextLine();
// seperate tag from line
list($tag, $line) = explode(' ', $line, 2);
return $line;
}
/**
* split a given line in tokens. a token is literal of any form or a list
*
* @param string $line line to decode
* @return array tokens, literals are returned as string, lists as array
* @throws Zend_Mail_Protocol_Exception
*/
protected function _decodeLine($line)
{
$tokens = array();
$stack = array();
/*
We start to decode the response here. The unterstood tokens are:
literal
"literal" or also "lit\\er\"al"
{bytes}<NL>literal
(literals*)
All tokens are returned in an array. Literals in braces (the last unterstood
token in the list) are returned as an array of tokens. I.e. the following response:
"foo" baz {3}<NL>bar ("f\\\"oo" bar)
would be returned as:
array('foo', 'baz', 'bar', array('f\\\"oo', 'bar'));
// TODO: add handling of '[' and ']' to parser for easier handling of response text
*/
// replace any trailling <NL> including spaces with a single space
$line = rtrim($line) . ' ';
while (($pos = strpos($line, ' ')) !== false) {
$token = substr($line, 0, $pos);
while ($token[0] == '(') {
array_push($stack, $tokens);
$tokens = array();
$token = substr($token, 1);
}
if ($token[0] == '"') {
if (preg_match('%^"((.|\\\\|\\")*?)" *%', $line, $matches)) {
$tokens[] = $matches[1];
$line = substr($line, strlen($matches[0]));
continue;
}
}
if ($token[0] == '{') {
$endPos = strpos($token, '}');
$chars = substr($token, 1, $endPos - 1);
if (is_numeric($chars)) {
$token = '';
while (strlen($token) < $chars) {
$token .= $this->_nextLine();
}
$line = '';
if (strlen($token) > $chars) {
$line = substr($token, $chars);
$token = substr($token, 0, $chars);
} else {
$line .= $this->_nextLine();
}
$tokens[] = $token;
$line = trim($line) . ' ';
continue;
}
}
if ($stack && $token[strlen($token) - 1] == ')') {
// closing braces are not seperated by spaces, so we need to count them
$braces = strlen($token);
$token = rtrim($token, ')');
// only count braces if more than one
$braces -= strlen($token) + 1;
// only add if token had more than just closing braces
if ($token) {
$tokens[] = $token;
}
$token = $tokens;
$tokens = array_pop($stack);
// special handline if more than one closing brace
while ($braces-- > 0) {
$tokens[] = $token;
$token = $tokens;
$tokens = array_pop($stack);
}
}
$tokens[] = $token;
$line = substr($line, $pos + 1);
}
// maybe the server forgot to send some closing braces
while ($stack) {
$child = $tokens;
$tokens = array_pop($stack);
$tokens[] = $child;
}
return $tokens;
}
/**
* read a response "line" (could also be more than one real line if response has {..}<NL>)
* and do a simple decode
*
* @param array|string $tokens decoded tokens are returned by reference, if $dontParse
* is true the unparsed line is returned here
* @param string $wantedTag check for this tag for response code. Default '*' is
* continuation tag.
* @param bool $dontParse if true only the unparsed line is returned $tokens
* @return bool if returned tag matches wanted tag
* @throws Zend_Mail_Protocol_Exception
*/
public function readLine(&$tokens = array(), $wantedTag = '*', $dontParse = false)
{
$line = $this->_nextTaggedLine($tag);
if (!$dontParse) {
$tokens = $this->_decodeLine($line);
} else {
$tokens = $line;
}
// if tag is wanted tag we might be at the end of a multiline response
return $tag == $wantedTag;
}
/**
* read all lines of response until given tag is found (last line of response)
*
* @param string $tag the tag of your request
* @param string|array $filter you can filter the response so you get only the
* given response lines
* @param bool $dontParse if true every line is returned unparsed instead of
* the decoded tokens
* @return null|bool|array tokens if success, false if error, null if bad request
* @throws Zend_Mail_Protocol_Exception
*/
public function readResponse($tag, $dontParse = false)
{
$lines = array();
while (!$this->readLine($tokens, $tag, $dontParse)) {
$lines[] = $tokens;
}
if ($dontParse) {
// last to chars are still needed for response code
$tokens = array(substr($tokens, 0, 2));
}
// last line has response code
if ($tokens[0] == 'OK') {
return $lines ? $lines : true;
} else if ($tokens[0] == 'NO'){
return false;
}
return null;
}
/**
* send a request
*
* @param string $command your request command
* @param array $tokens additional parameters to command, use escapeString() to prepare
* @param string $tag provide a tag otherwise an autogenerated is returned
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function sendRequest($command, $tokens = array(), &$tag = null)
{
if (!$tag) {
++$this->_tagCount;
$tag = 'TAG' . $this->_tagCount;
}
$line = $tag . ' ' . $command;
foreach ($tokens as $token) {
if (is_array($token)) {
if (@fputs($this->_socket, $line . ' ' . $token[0] . "\r\n") === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
}
if (!$this->_assumedNextLine('+ OK')) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot send literal string');
}
$line = $token[1];
} else {
$line .= ' ' . $token;
}
}
if (@fputs($this->_socket, $line . "\r\n") === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
}
}
/**
* send a request and get response at once
*
* @param string $command command as in sendRequest()
* @param array $tokens parameters as in sendRequest()
* @param bool $dontParse if true unparsed lines are returned instead of tokens
* @return mixed response as in readResponse()
* @throws Zend_Mail_Protocol_Exception
*/
public function requestAndResponse($command, $tokens = array(), $dontParse = false)
{
$this->sendRequest($command, $tokens, $tag);
$response = $this->readResponse($tag, $dontParse);
return $response;
}
/**
* escape one or more literals i.e. for sendRequest
*
* @param string|array $string the literal/-s
* @return string|array escape literals, literals with newline ar returned
* as array('{size}', 'string');
*/
public function escapeString($string)
{
if (func_num_args() < 2) {
if (strpos($string, "\n") !== false) {
return array('{' . strlen($string) . '}', $string);
} else {
return '"' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $string) . '"';
}
}
$result = array();
foreach (func_get_args() as $string) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -