如何从套接字流中读取多行?

时间:2013-03-18 11:34:05

标签: php imap

我想从gmails的imap服务器检索电子邮件,但问题是来自服务器的响应是多行(如所示here)而fgets只检索一行。

我尝试过使用fgets,fread,socket_read,但是没有一个工作,所以要么我使用了错误的方法,要么使用方法不正确。我也尝试了this教程,但它也没有用。如果有人能帮助我,我将不胜感激。

谢谢,如果这是一个业余问题,我真的很抱歉。

代码:

<?php

$stuff = fsockopen('ssl://imap.gmail.com',993);
$reply = fgets($stuff,4096);
echo 'connection: '.$reply.'<br/>';

$request = fputs($stuff,"a1 LOGIN MyUserName Password\r\n");
$receive = socket_read($stuff, 4096);

echo 'login: '.$receive.'<br/>';


$request = fputs($stuff,"a2 EXAMINE INBOX\r\n");
$reply = '';

while(!feof($stuff))
    $reply .= fread($stuff, 4096);

echo $reply;



/*
$request = fputs($stuff,'a3 FETCH 1 BODY[]\r\n');
$reply = fgets($stuff);
echo $reply;
*/
?>

以下Max的答案有效。这是我的实现。

private function Response($instructionNumber)
{
    $end_of_response = false;

    while (!$end_of_response)
    {
        $line = fgets($this->connection,self::responseSize);
        $response .= $line.'<br/>';

        if(preg_match("/$instructionNumber (OK|NO|BAD)/", $response,$responseCode))
            $end_of_response = true;
    }

    return array('code' => $responseCode[1],
        'response'=>$response);
}

2 个答案:

答案 0 :(得分:3)

自从我编写PHP以来已经有一段时间了,我对IMAP知之甚少,但如果它与NNTP类似,那么你的代码看起来就像这样(在SO编辑器中写的,可能会被窃听) :

$buffer = '';
function read_line($socket) {
    global $buffer;
    while (strpos($buffer, "\n") === false)
        $buffer .= fread($socket, 1024);

    $lineEnd = strpos($buffer, "\n");
    $line = substr($buffer, 0, $lineEnd-1);
    $buffer = substr($buffer, $lineEnd);

    return $line;
}

function send_line($socket, $line) {
    fwrite($socket, $line);
}

$socket = fsockopen('ssl://imap.gmail.com',993);
$welcome = read_line($socket);

send_line("a1 LOGIN MyUserName Password\r\n");
$reply = read_line($socket);

send_line("a2 EXAMINE INBOX\r\n");
while (($reply = trim(read_line($socket))) != '.') {
    echo $reply.PHP_EOL;
}

echo "Done";

基本概念是:

  • 始终缓冲所有传入数据。 PHP不能很好地处理行,所以自己拆分。
  • 不要随意阅读所有内容,但要知道会发生什么。您希望有一个欢迎行,LOGIN有一个回复,并且EXAMINE INBOX会一直输出数据,直到有一个点,所以一看到就立即停止阅读。
  • 你很可能想要一个简单的功能来处理阅读。您甚至可以编写另一个功能来简化:

function read_block($socket) {
    $block = '';
    while ('.' != trim($reply = read_line($socket)) {
        $block .= $reply;
    }
    return $block;
}

答案 1 :(得分:2)

通常,您知道在收到所发送标签的OK / BAD / NO响应时停止阅读。如果您发送a1 LOGIN ...,则会在a1 OK/BAD/NO ...时停止。