<?php namespace Lib\Imap; class ImapClient { /** * 资源 * @var resource|false */ private $socket; protected bool $debug = false; protected string $host; /** * 每请求一次就会+1 * @var int */ public int $tagNum = 0; /** * 是否是非阻塞模式 * @var bool */ public $isBlocking = false; public function __construct(string $host){ $this->host = $host; $this->socket = false; } public function open(){ $content = stream_context_create([ 'ssl' => [ 'verify_peer' => false, // 有的证书和域名不匹配,这里关闭认证 'verify_peer_name' => false,// 有的证书和域名不匹配,这里关闭认证 ] ]); $flags = STREAM_CLIENT_CONNECT; $this->socket = stream_socket_client( $this->host, $errno, $error, 30, $flags, $content ); if($error){ throw new \Exception($error); } if (!$this->socket) { throw new \Exception($this->host." connection fail."); } // 设置为非阻塞模式 $this->isBlocking = stream_set_blocking($this->socket, false); } /** * @param bool $debug * @return $this * @author:dc * @time 2024/9/18 9:57 */ public function setDebug(bool $debug = true): static { $this->debug = $debug; return $this; } /** * 写 * @param string $cmd * @return false|int * @author:dc * @time 2024/9/13 15:47 */ protected function write(string $cmd){ if($this->debug){ echo 'write: '.$cmd; } $totalBytes = strlen($cmd); $bytesWritten = 0; $maxW = 50; while ($bytesWritten < $totalBytes) { $result = fwrite($this->socket, substr($cmd, $bytesWritten)); // 写失败了 if ($result === false) { return false; } // 更新已写入的字节数 $bytesWritten += $result; // 如果没有写入任何字节,可能是缓冲区满了,稍后再试 if ($result === 0) { $maxW--; if(!$maxW){ throw new \Exception('socket write error time out'); } // 兼容下swoole if(function_exists('go') && \co::getCid()>0){ \co::sleep(0.1); }else{ // 等待 100 毫秒 usleep(100000); } } } return $bytesWritten; } /** * 读 * @return false|string * @author:dc * @time 2024/9/13 15:49 */ protected function readLine(){ $i = 50; // 非阻塞模式下,只等待5秒,没返回数据就返回 $str = false; while ($i>0){ $str = fgets($this->socket,2048); // 非阻塞模式 if($this->isBlocking && $str === false){ $i--; // 兼容下swoole if(function_exists('go') && \co::getCid()>0){ \co::sleep(0.1); }else{ // 等待 100 毫秒 usleep(100000); } }else{ break; } } // 超时了,异常 if(!$i && $str===false){ throw new \Exception('read time out'); } if($this->debug){ echo 'read: '.$str; } return $str; } /** * * @param string $cmd 执行的命令 * @return array * @author:dc * @time 2024/9/13 15:57 */ public function request(string $cmd):array { $this->tagNum++; $tag = 'TAG'.$this->tagNum; // 请求数据 $writeNumber = $this->write($tag.' '.$cmd."\r\n"); $result = []; if($writeNumber){ // 读取数据 while (1){ $line = $this->readLine(); $result[] = $line; list($token) = explode(' ',$line,2); // 结束了 if($token == $tag || $line === false){ break; } } } return $result; } public function __destruct() { if($this->socket) @fclose($this->socket); unset($this->socket); // TODO: Implement __destruct() method. } }