使用fgets/fread从fsockopen读取数据时卡住了

8

这是我正在使用的代码:

if (!($fp = fsockopen('ssl://imap.gmail.com', '993', $errno, $errstr, 15)))
    echo "Could not connect to host";
$server_response = fread($fp, 256);
echo $server_response;

fwrite($fp, "C01 CAPABILITY"."\r\n");
while (!feof($fp)) {
    echo fgets($fp, 256);
}

我收到了第一条回复:
OK Gimap ready for requests from xx.xx.xx.xx v3if9968808ibd.15 

但是页面超时了。我已经搜索了stream_set_blocking、stream_set_timeout、stream_select、fread等方法,但是仍然无法使其正常工作。我需要读取服务器发送的所有数据,然后执行其他命令(我将使用imap检索电子邮件)。

谢谢。


你确定响应只有256个字符吗?你确定套接字是可写的吗?如果套接字不可写,你的脚本可能会在fwrite()上挂起... - shadyyx
是的。我通过将while循环替换为简单的写入fgets($fp,256)两次来进行了测试。这是我得到的响应:* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH C01 OK - victor_golf
2个回答

8
你的脚本在 while 循环末尾挂起。这是因为你使用了 !feof() 作为循环条件,而服务器没有关闭连接。这意味着 feof() 总是会返回 false,而循环将永远继续下去。
当你编写完整的实现时,这不会成为问题,因为你将会查找响应代码并相应地跳出循环,例如:
<?php

  // Open a socket
  if (!($fp = fsockopen('ssl://imap.gmail.com', 993, $errno, $errstr, 15))) {
      die("Could not connect to host");
  }

  // Set timout to 1 second
  if (!stream_set_timeout($fp, 1)) die("Could not set timeout");

  // Fetch first line of response and echo it
  echo fgets($fp);

  // Send data to server
  echo "Writing data...";
  fwrite($fp, "C01 CAPABILITY\r\n");
  echo " Done\r\n";

  // Keep fetching lines until response code is correct
  while ($line = fgets($fp)) {
    echo $line;
    $line = preg_split('/\s+/', $line, 0, PREG_SPLIT_NO_EMPTY);
    $code = $line[0];
    if (strtoupper($code) == 'C01') {
      break;
    }
  }

  echo "I've finished!";

1
RFC(请求评论)是你的好朋友;-)(不要忘记处理错误响应,否则你的脚本将永远等待它永远不会收到的“C01”响应而挂起)。 - DaveRandom
是的。我已经花了一些时间研究这些命令。再次感谢。 - victor_golf

1

你的脚本应该是可以工作的。事实上,它正在工作。

当我运行你的代码时,请看下面的结果:

* OK Gimap ready for requests from xx.xx.xx.xx l5if4585958ebb.20
* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY  SASL-IR AUTH=XOAUTH
C01 OK Thats all she wrote! l5if4585958ebb.20

由于Gmail不会断开连接,也不会出现文件结束的情况。页面加载只是简单地超时。

换句话说:您的脚本将一直等待,直到Gmail断开连接,而这很不幸会在您的页面加载超时之后发生。


你是立刻得到结果了,还是需要等待一段时间(1-2分钟)才超时? - victor_golf
问题可能是你正在尝试从网页运行它,对吗? 页面在 Gmail 断开连接之前超时(因此 feof() 永远不会返回 true)。它可能会在超时过程中丢失部分缓冲区。 - Woutifier
是的,我有一个.php页面,其中包含这段代码。问题出在哪里? - victor_golf
我收到了以下响应,但在加载页面2分钟后:
  • OK Gimap准备好从xx.xx.xx.xx vb10if10168308icb.24请求 * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH C01 OK Thats all she wrote! vb10if10168308icb.24
由于stream_set_timeout($fp,1)似乎不起作用,我该如何处理超时?
- victor_golf
好吧,这只是一种解决方案,但前提是服务器响应如预期般成功。如果出现错误,页面仍会挂起,该怎么办呢?并且正如我提到的,我将检索电子邮件,所以仅检查“OK”可能不是一个好的解决方案。我是对的吗? - victor_golf
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接