zoukankan      html  css  js  c++  java
  • [PHP] PHP调用IMAP协议读取邮件类库

    socket.php 为连接socket的类库

    imap.php 基于socket的imap协议封装

    test.php 进行测试

    require_once 'socket.php';
    require_once 'imap.php';
    $imap=new Sina_Mail_Net_Imap("imap.sina.net:143",30,30);
    $imap->capability();
    $imap->id(array(
        'name'          => 'SinaMail OtherMail Client',
        'version'       => '1',
        'os'            => 'SinaMail OtherMail',
        'os-version'    => '1.0',
    ));
    $imap->login("xxxx@xxxxx","xxxx");
    $folders=$imap->getList('', '*');
    var_dump($folders);
    $status = $imap->select('SENT');
    var_dump($status);
    $ls = $imap->fetch(array(), array('uid', 'internaldate', 'rfc822.size'));
    
    
    
    
    foreach($ls as $k=>$i){
        $info=$imap->fetch(array($k), array('rfc822'));
    }

    imap.php

    <?php
    class Sina_Mail_Net_Imap {
        const MAX_READ_SIZE = 100000000;
        const PATTERN_REQUEST_STRING_SEQUENCE   = '/{d+}/';
        const PATTERN_RESPONSE_STRING_SEQUENCE  = '/{(d+)}$/';
        const SEQUENCE_PARAM_NAME   = '[]';
        const PARTIAL_PARAM_NAME    = '<>';
        const PARAM_NO          = 1;
        const PARAM_SINGLE      = 2;
        const PARAM_PAIR        = 4;
        const PARAM_LIST        = 8;
        const PARAM_STRING      = 16;
        const PARAM_NUMBER      = 32;
        const PARAM_DATE        = 64;
        const PARAM_FLAG        = 128;
        const PARAM_SEQUENCE    = 256;
        const PARAM_SEARCH      = 512;
        const PARAM_BODY        = 1024;
        const PARAM_PARTIAL     = 2048;
        const PARAM_EXCLUSIVE   = 4096;
        private static $statusKeywords = array(
            'MESSAGES'      => self::PARAM_NO,
            'RECENT'        => self::PARAM_NO,
            'UIDNEXT'       => self::PARAM_NO,
            'UIDVALIDITY'   => self::PARAM_NO,
            'UNSEEN'        => self::PARAM_NO,
        );
        private static $searchKeywords = array(
            'ALL'           => self::PARAM_NO,
            'ANSWERED'      => self::PARAM_NO,
            'BCC'           => 18, // self::PARAM_SINGLE | self::PARAM_STRING,
            'BEFORE'        => 66, // self::PARAM_SINGLE | self::PARAM_DATE,
            'BODY'          => 18, // self::PARAM_SINGLE | self::PARAM_STRING,
            'CC'            => 18, // self::PARAM_SINGLE | self::PARAM_STRING,
            'DELETED'       => self::PARAM_NO,
            'DRAFT'         => self::PARAM_NO,
            'FLAGGED'       => self::PARAM_NO,
            'FROM'          => 18, // self::PARAM_SINGLE | self::PARAM_STRING,
            'HEADER'        => 20, // self::PARAM_PAIR | self::PARAM_STRING,
            'KEYWORD'       => 130, // self::PARAM_SINGLE | self::PARAM_FLAG,
            'LARGER'        => 34, // self::PARAM_SINGLE | self::PARAM_NUMBER,
            'NEW'           => self::PARAM_NO,
            'NOT'           => 514, // self::PARAM_SINGLE | self::PARAM_SEARCH,
            'OLD'           => self::PARAM_NO,
            'ON'            => 66, // self::PARAM_SINGLE | self::PARAM_DATE,
            'OR'            => 516, // self::PARAM_PAIR | self::PARAM_SEARCH,
            'RECENT'        => self::PARAM_NO,
            'SEEN'          => self::PARAM_NO,
            'SENTBEFORE'    => 66, // self::PARAM_SINGLE | self::PARAM_DATE,
            'SENTON'        => 66, // self::PARAM_SINGLE | self::PARAM_DATE,
            'SENTSINCE'     => 66, // self::PARAM_SINGLE | self::PARAM_DATE,
            'SINCE'         => 66, // self::PARAM_SINGLE | self::PARAM_DATE,
            'SMALLER'       => 34, // self::PARAM_SINGLE | self::PARAM_NUMBER,
            'SUBJECT'       => 18, // self::PARAM_SINGLE | self::PARAM_STRING,
            'TEXT'          => 18, // self::PARAM_SINGLE | self::PARAM_STRING,
            'TO'            => 18, // self::PARAM_SINGLE | self::PARAM_STRING,
            'UID'           => 258, // self::PARAM_SINGLE | self::PARAM_SEQUENCE,
            'UNANSWERED'    => self::PARAM_NO,
            'UNDELETED'     => self::PARAM_NO,
            'UNDRAFT'       => self::PARAM_NO,
            'UNFLAGGED'     => self::PARAM_NO,
            'UNKEYWORD'     => 130, // self::PARAM_SINGLE | self::PARAM_FLAG,
            'UNSEEN'        => self::PARAM_NO,
        );
        private static $fetchKeywords = array(
            'ALL'           => 4097, // self::PARAM_NO | self::PARAM_EXCLUSIVE,
            'FAST'          => 4097, // self::PARAM_NO | self::PARAM_EXCLUSIVE,
            'FULL'          => 4097, // self::PARAM_NO | self::PARAM_EXCLUSIVE,
            'BODY'          => 3075, // self::PARAM_NO | self::PARAM_SINGLE | self::PARAM_BODY | self::PARAM_PARTIAL,
            'BODY.PEEK'     => 3074, // self::PARAM_SINGLE | self::PARAM_BODY | self::PARAM_PARTIAL,
            'BODYSTRUCTURE' => self::PARAM_NO,
            'ENVELOPE'      => self::PARAM_NO,
            'FLAGS'         => self::PARAM_NO,
            'INTERNALDATE'  => self::PARAM_NO,
            'RFC822'        => self::PARAM_NO,
            'RFC822.HEADER' => self::PARAM_NO,
            'RFC822.SIZE'   => self::PARAM_NO,
            'RFC822.TEXT'   => self::PARAM_NO,
            'UID'           => self::PARAM_NO,
        );
        private $sock = null;
        private $timeout = 120;
        private $ts = 0;
        private $tagName = 'A';
        private $tagId = 0;
        private $capabilities = array();
        private $folders = array();
        private $currentFolder = null;
        private $currentCommand = null;
        private $lastSend = '';
        private $lastRecv = '';
        public function __construct($uri, $timeout = null, $connTimeout = null) {
            $this->sock = new Socket($uri, $timeout);        
    //        $t = intval($timeout);
    //        if ($t > 0) {
    //            $this->timeout = $t;
    //        }
            $this->connect($connTimeout);        
        }
        public function __destruct() {
        }
    
        public function connect($timeout) {        
            $this->sock->connect($timeout);        
            $this->getResponse();
        }
        
        public function capability() {
            $res = $this->request('capability');
            if (isset($res[0][0]) && $res[0][0] == '*' &&
                isset($res[0][1]) && strcasecmp($res[0][1], 'capability') == 0) {
                for ($i = 2, $n = count($res[0]); $i < $n; ++$i) {
                    $this->capabilities[strtoupper($res[0][$i])] = true;
                }
            }        
        }
        
        public function id($data) {
            if (isset($this->capabilities['ID'])) {            
                $this->request('id', array($data));            
            }        
        }
        public function login($username, $password) {
            try {
                $this->request('login', array($username, $password));
            } catch (Exception $ex) {
                throw new Exception($ex->getMessage(), $ex->getCode());
            }
        }
        
        public function logout() {
            $this->request('logout');        
        }
        
        public function getList($reference = '', $wildcard = '') {
            $res = $this->request('list', array($reference, $wildcard));
            foreach ($res as &$r) {
                if (isset($r[0]) && $r[0] == '*' && 
                    isset($r[1]) && strcasecmp($r[1], 'list') == 0 && 
                    isset($r[4])) {
                    $this->folders[$r[4]] = array(
                        'id'    => $r[4],
                        'name'  => mb_convert_encoding($r[4], 'UTF-8', 'UTF7-IMAP'),
                        'path'  => $r[3],
                        'attr'  => $r[2],
                    );
                }
            }
            return $this->folders;
        }
        
        public function status($folder, $data) {
            $args = $this->formatArgsForCommand($data, self::$statusKeywords);
            $res = $this->request('status', array($folder, $args));
            $status = array();
            if (!empty($res)) {            
                foreach ($res as &$r) {
                    if (isset($r[0]) && $r[0] == '*' && 
                        isset($r[1]) && strcasecmp($r[1], 'status') == 0 && 
                        isset($r[3]) && is_array($r[3])) {
                        for ($i = 0, $n = count($r[3]); $i < $n; $i += 2) {
                            $status[$r[3][$i]] = $r[3][$i + 1];
                        }
                    }
                }
            }
            return $status;
        }
        public function select($folder) {
            $res = $this->request('select', array($folder));
            $status = array();
            if (!empty($res)) {
                foreach ($res as $r) {
                    if (isset($r[0]) && $r[0] == '*') {
                        if (isset($r[1]) && isset($r[2])) {
                            if (strcasecmp($r[1], 'ok') == 0 && is_array($r[2])) {
                                for ($i = 0, $n = count($i); $i < $n; $i += 2) {
                                    $status[$r[2][$i]] = $r[2][$i + 1];
                                }
                            } elseif (ctype_digit($r[1])) {
                                $status[$r[2]] = $r[1];
                            } else {
                                $status[$r[1]] = $r[2];
                            }    
                        }
                    }
                }
            }
            $this->currentFolder = $folder;
            return $status;
        }
        public function search($data) {     
            $args = $this->formatArgsForCommand($data, self::$searchKeywords, true);                
            $res = $this->request('search', $args);
            $ls = array();
            foreach ($res as &$r) {
                if (isset($r[0]) && $r[0] == '*' && 
                    isset($r[1]) && strcasecmp($r[1], 'search') == 0) {
                    for ($i = 2, $n = count($r); $i < $n; ++$i) {
                        $ls[] = $r[$i];
                    }
                }
            }
            return $ls;
        }
        public function fetch($seq, $data) {                        
            $seqStr = $this->formatSequence($seq);        
            $args = $this->formatArgsForCommand($data, self::$fetchKeywords);                                
            $res = $this->request('fetch', array($seqStr, $args));
    //        var_dump($res);
            $ls = array();
            foreach ($res as &$r) {
                if (isset($r[0]) && $r[0] == '*' &&
                    isset($r[1]) && is_numeric($r[1]) && 
                    isset($r[2]) && strcasecmp($r[2], 'fetch') == 0 &&
                    isset($r[3]) && is_array($r[3])) {
                    $a = array();
                    for ($i = 0, $n = count($r[3]); $i < $n; $i += 2) {
                        $key = $r[3][$i];
                        if (((strcasecmp($key, 'BODY') == 0 && isset($args['BODY']) && is_array($args['BODY'])) || 
                             (strcasecmp($key, 'BODY.PEEK') == 0 && isset($args['BODY.PEEK']) && is_array($args['BODY.PEEK']))) && 
                            is_array($r[3][$i + 1])) {
                            $key = trim($this->formatRequestArray(array($key => $r[3][$i + 1]), $placeHolder, 0), '()');
                            $i++;
                        } else {
                            $key = $r[3][$i];
                        }
                        $a[$key] = $r[3][$i + 1];
                    }
                    if (!empty($a)) {
                        $ls[$r[1]] = $a;
                    }
                }
            }
            return $ls;
        }
        private function nextTag() {
            $this->tagId++;
            return sprintf('%s%d', $this->tagName, $this->tagId);
        }
        private function request($cmd, $args = array()) {                
            $this->currentCommand = strtoupper(trim($cmd));
            $tag = $this->nextTag();
            $req = $tag . ' ' . $this->currentCommand;
            
            // 格式化参数列表
            $strSeqList = array();
            if (is_array($args)) {
                $argStr = $this->formatRequestArray($args, $strSeqList);                
            } else {                
                $argStr = $this->formatRequestString($args, $strSeqList);
            }
            //$argStr = $this->makeRequest($args, $strSeqList);
            $subReqs = array();
            if (isset($argStr[0])) {
                $req .= ' ' . $argStr;
                // 如果参数中包括需要序列化的数据,根据序列化标识{length}将命令拆分成多条
                if (!empty($strSeqList) && preg_match_all(self::PATTERN_REQUEST_STRING_SEQUENCE, $req, $matches, PREG_OFFSET_CAPTURE)) {
                    $p = 0;
                    foreach ($matches[0] as $m) {
                        $e = $m[1] + strlen($m[0]);
                        $subReqs[] = substr($req, $p, $e - $p);                    
                        $p = $e;
                    }
                    $subReqs[] = substr($req, $p);
                    // 校验序列化标识与需要序列化的参数列表数量是否一致
                    if (count($subReqs) != count($strSeqList) + 1) {
                        $subReqs = null;
                    }
                }
            }
                    
            if (empty($subReqs)) {
                // 处理单条命令
                $this->sock->writeLine($req);
                $this->lastSend = $req;        
                $res = $this->getResponse($tag);
            } else {            
                // 处理多条命令
                $this->lastSend = '';
                foreach ($subReqs as $id => $req) {
                    $this->sock->writeLine($req);                          
                    $this->lastSend .= $req;
                    $res = $this->getResponse($tag);                
                    if (isset($res[0][0]) && $res[0][0] == '+') {
                        $this->sock->write($strSeqList[$id]);                
                        $this->lastSend .= "
    " . $strSeqList[$id];
                    } else {
                        // 如果服务器端返回其他相应,则定制后续执行
                        break;
                    }
                }                
            }
            return $res;
        }
            
        private function formatRequestString($s, &$strSeqList) {
            $s = trim($s);
            $needQuote = false;
            if (!isset($s[0])) {
                $needQuote = true;
            } elseif ($this->currentCommand == 'ID') {    
                $needQuote = true;
            } else {
                // 参数包含多行时,需要进行序列化
                if (strpos($s, "
    ") !== false || strpos($s, "
    ") !== false) {                
                    $strSeqList[] = $s;
                    $s = sprintf('{%d}', strlen($s));
                } else {
                    // 参数包含双引号或空格时,需要将使用双引号括起来
                    if (strpos($s, '"') !== false) {
                        $s = addcslashes($s, '"');
                        $needQuote = true;
                    }
                    if (strpos($s, ' ') !== false) {
                        $needQuote = true;
                    }
                }
            }
            if ($needQuote) {
                return sprintf('"%s"', $s);
            } else {
                return $s;
            }
        }
        private function formatRequestArray($arr, &$strSeqList, $level = -1) {
            $a = array();
            foreach ($arr as $k => $v) {
                $isBody = false;
                $supportPartial = false;
                $partialStr = '';
                if ($this->currentCommand == 'FETCH') {
                    // 识别是否body命令,是否可以包含<partial>
                    $kw = strtoupper($k);            
                    if (isset(self::$fetchKeywords[$kw]) && (self::$fetchKeywords[$kw] & self::PARAM_BODY) > 0) {
                        $isBody = true;
                    }
                    if (isset(self::$fetchKeywords[$kw]) && (self::$fetchKeywords[$kw] & self::PARAM_PARTIAL) > 0) {
                        $supportPartial = true;
                    }
                }                        
                if (is_array($v)) {                        
                    if ($supportPartial && isset($v[self::PARTIAL_PARAM_NAME]) && is_array($v[self::PARTIAL_PARAM_NAME])) {                    
                        // 处理包含<partial>的命令
                        foreach ($v[self::PARTIAL_PARAM_NAME] as $spos => $mlen) {
                            $partialStr =  sprintf('<%d.%d>', $spos, $mlen);
                        }                    
                        unset($v[self::PARTIAL_PARAM_NAME]);
                    }
                    $s = $this->formatRequestArray($v, $strSeqList, $level + 1);
                } else {
                    $s = $this->formatRequestString($v, $strSeqList);
                }            
                if (!is_numeric($k)) {
                    // 字典方式需要包含键名
                    $k = $this->formatRequestString($k, $strSeqList);
                    if ($isBody) {
                        $s = $k . $s;                    
                    } else {
                        $s = $k . ' ' . $s;
                    }
                    // 包含<partial>
                    if ($supportPartial) {
                        $s .= $partialStr;
                    }
                }
                $a[] = $s;
            }
            if ($level < 0) {
                return implode(' ', $a);
            } elseif (($level % 2) == 0) {
                return sprintf('(%s)', implode(' ', $a));
            } else {
                return sprintf('[%s]', implode(' ', $a));
            }
        }
        private function formatSequence($seq) {
            $n = count($seq);
            if ($n == 0) {
                return '1:*';            
            } elseif ($n == 1) {
                if (isset($seq[0])) {
                    return strval($seq[0]);
                } else {
                    foreach ($seq as $k => $v) {
                        return $k . ':' . $v;
                    }
                }
            } else {
                return implode(',', $seq);
            }
        }
        private function formatArgsForCommand(&$data, &$fields, $asList = false) {
            $args = array();
            foreach ($data as $k => $v) {            
                if (is_numeric($k)) {
                    // 无值参数
                    $name = strtoupper($v);
                    if (isset($fields[$name])) {
                        // 对于排他性属性,直接返回
                        if (($fields[$name] & self::PARAM_EXCLUSIVE) > 0) {
                            return $name;
                        } elseif (($fields[$name] & self::PARAM_NO) > 0) {                
                            $args[] = $name;
                        }
                    }
                } elseif ($k == self::SEQUENCE_PARAM_NAME) {
                    // 序列
                    $args[] = $this->formatSequence($v);                
                } else {
                    $name = strtoupper($k);
                    if (isset($fields[$name])) {
                        $paramType = $fields[$name];                    
                        // 格式化参数类型
                        if (($paramType & self::PARAM_DATE) > 0) {
                            $v = date('j-M-Y', $v);
                        } elseif (($paramType & self::PARAM_SEQUENCE) > 0) {
                            $v = $this->formatSequence($v);
                        }                        
    
                        // 根据参数定义拼组参数列表
                        if (($paramType & self::PARAM_SINGLE) > 0) {
                            // 单值参数
                            if ($asList) {
                                $args[] = $name;
                                $args[] = $v;
                            } else {
                                $args[$name] = $v;
                            }
                        } elseif (($paramType & self::PARAM_PAIR) > 0) {
                            // 键值对参数
                            if (is_array($v)) {
                                foreach ($v as $x => $y) {
                                    $pk = $x;
                                    $pv = $y;
                                    break;
                                }
                            } else {
                                $pk = $v;
                                $pv = '';
                            }
                            if ($asList) {
                                $args[] = $name;
                                $args[] = $pk;
                                $args[] = $pv;
                            } else {
                                $args[$name] = array($pk => $pv);
                            }
                        } elseif (($paramType & self::PARAM_LIST) > 0) {
                            // 列表参数
                            if ($asList) {
                                $args[] = $name;
                                foreach ($v as $i) {
                                    $args[] = $i;
                                }
                            } else {
                                $args[$name] = $v;
                            }
                        } elseif (($paramType & self::PARAM_NO) > 0) {
                            // 无值参数
                            $args[] = $name;
                        }
                    }
                }
            }
            return $args;
        }
        private function getResponse($tag = null) {
            $r = array();
            $readMore = true;  
            while ($readMore) {
                $ln = trim($this->sock->readLine());            
                if (!isset($ln[0])) {
                    // connection closed or read empty string, throw exception to avoid dead loop and reconnect
                    throw new Exception('read response failed');
                }
                
                $matches = null;
                $strSeqKey = null;
                $strSeq = null;
                if (preg_match(self::PATTERN_RESPONSE_STRING_SEQUENCE, $ln, $matches)) {
                    $strSeqKey = $matches[0];
                    $this->readSequence($ln, $strSeq, $matches[1]);
                }
                $this->lastRecv = $ln;
                
                // 区分处理不同种响应
                switch ($ln[0]) {
                    case '*':
                        $r[] = $this->parseLine($ln, $strSeqKey, $strSeq);                                        
                        if (!$tag) {
                            $readMore = false;
                        }
                        break;
                    case $this->tagName:
                        $r[] = $this->parseLine($ln);
                        if ($tag) {
                            $readMore = false;
                        } else {
                            
                        }
                        break;
                    case '+':
                        $r[] = $this->parseLine($ln);
                        $readMore = false;
                        break;
                    default:
                        $r[] = $ln;
                        break;
                }                        
            }        
            
            //var_dump($this->lastSend, $this->lastRecv);
            
            // 无响应数据
            if (empty($r)) {
                throw new Exception('no response');
            }
                                                    
            $last = $r[count($r) - 1];
            if (isset($last[0]) && $last[0] == '+') {
                // 继续发送请求数据
            } else {
                if ($tag) {
                    if (!isset($last[0]) || strcasecmp($last[0], $tag) != 0) {                    
                        throw new Exception('tag no match');
                    }           
                } else {
                    if (!isset($last[0]) || strcasecmp($last[0], '*') != 0) {                    
                        throw new Exception('untag no match');
                    }
                }
                if (isset($last[1])) {
                    // 处理响应出错的情况
                    if (strcasecmp($last[1], 'bad') == 0) {        
                        throw new Exception(implode(' ', $last));
                    } elseif (strcasecmp($last[1], 'no') == 0) {
                        throw new Exception(implode(' ', $last));
                    }
                }
                //$this->currentCommand = null;
            }
            
            return $r;
        }
        
        private function readSequence(&$ln, &$strSeq, $seqLength) {
            // 对于字符串序列,读取完整内容后再拼接响应        
            $readLen = 0;
            $st = microtime(true);
            // 网络请求多次读取字符串序列内容,直到读好为止
            while ($readLen < $seqLength) {
                $sb = $this->sock->read($seqLength - $readLen);
                if (isset($sb[0])) {
                    $strSeq .= $sb;
                    $readLen = strlen($strSeq);
                }                    
                if ((microtime(true) - $st) > $this->timeout) {
                    throw new Exception('read sequence timeout');
                }
            }
            // 读取字符串序列后的剩余命令
            $leftLn = rtrim($this->sock->readLine());
            $ln = $ln . $leftLn;
        }
        
        private function parseLine($ln, $strSeqKey = null, $strSeq = null) {
            $r = array();
            $p =& $r;
            $stack = array();
            $token = '';
            $escape = false;
            $inQuote = false;
            for ($i = 0, $n = strlen($ln); $i < $n; ++$i) {
                $ch = $ln[$i];
                if ($ch == '"') {
                    // 处理双引号括起的字符串
                    if (!$inQuote) {
                        $inQuote = true;
                    } else {
                        $inQuote = false;
                    }
                } elseif ($inQuote) {
                    // 对于括起的字符串,处理双引号转义
                    if ($ch == '\') {
                        if (!$escape && isset($ln[$i + 1]) && $ln[$i + 1] == '"') {               
                            $token .= '"';
                            $i++;
                        } else {
                            $token .= $ch;
                            $escape = !$escape;
                        }                    
                    } else {
                        $token .= $ch;
                    }
                } elseif ($ch == ' ' || 
                    $ch == '(' || $ch == ')' || 
                    $ch == '[' || $ch == ']') {
                    // 处理子列表
                    if (isset($token[0])) {
                        // 将字符串序列标识:{length},替换为真实字符串
                        if ($strSeqKey && $token == $strSeqKey) {
                            $p[] = $strSeq;
                        } else {
                            $p[] = $token;
                        }
                        $token = '';
                    }                
                    if ($ch == '(' || $ch == '[') {                    
                        $p[] = array();
                        $stack[] =& $p;
                        $p =& $p[count($p) - 1];                                        
                    } elseif ($ch == ')' || $ch == ']') {        
                        $p =& $stack[count($stack) - 1];
                        array_pop($stack);
                    }
                } else {                
                    // 处理字符串字面量
                    $token .= $ch;
                }            
            }
            if (isset($token[0])) {
                // 将字符串序列标识:{length},替换为真实字符串
                if ($strSeqKey && $token == $strSeqKey) {
                    $p[] = $strSeq;
                } else {
                    $p[] = $token;
                }
            }
            return $r;
        }
    }
    
    // end of php

    socket.php

    <?php
    class Socket{
        const DEFAULT_READ_SIZE = 8192;
        const CRTL = "
    ";
        private $uri = null;
        private $timeout = null;
        private $sock = null;
        private $connected = false;
        public function __construct($uri, $timeout = null){
            $this->uri = $uri;
            $this->timeout = $this->formatTimeout($timeout);
        }
    
        public function connect($timeout = null, $retryTimes = null){
            if ($this->connected) {
                $this->close();
            }
    
            $connTimeout = $this->formatTimeout($timeout, $this->timeout);
            $retryTimes = intval($retryTimes);
            if ($retryTimes < 1) {
                $retryTimes = 1;
            }
            for ($i = 0; $i < $retryTimes; ++$i) {
                $this->sock = stream_socket_client(
                    $this->uri, $errno, $error, $connTimeout);
                if ($this->sock) {
                    break;
                }
            }
            if (!$this->sock) {
    
            }
            stream_set_timeout($this->sock, $this->timeout);
            $this->connected = true;
        }
    
        public function read($size){
            assert($this->connected);
    
            $buf = fread($this->sock, $size);
            if ($buf === false) {
                $this->handleReadError();
            }
    
            return $buf;
        }
    
        public function readLine(){
            assert($this->connected);
            $buf = '';
            while (true) {
                $s = fgets($this->sock, self::DEFAULT_READ_SIZE);
                if ($s === false) {
                    $this->checkReadTimeout();
                    break;
                }
                $n = strlen($s);
                if (!$n) {
                    break;
                }
                $buf .= $s;
                if ($s[$n - 1] == "
    ") {
                    break;
                }
            }
    
            return $buf;
        }
    
        public function readAll(){
            assert($this->connected);
            $buf = '';
            while (true) {
                $s = fread($this->sock, self::DEFAULT_READ_SIZE);
                if ($s === false) {
                    $this->handleReadError();
                }
    
                if (!isset($s[0])) {
                    break;
                }
    
                $buf .= $s;
            }
    
            return $buf;
        }
    
        public function write($s){
            assert($this->connected);
            $n = strlen($s);
            $w = 0;
            while ($w < $n) {
                $buf = substr($s, $w, self::DEFAULT_READ_SIZE);
                $r = fwrite($this->sock, $buf);
                if (!$r) {
                    $this->close();
                }
                $w += $r;
            }
        }
        public function writeLine($s){
            $this->write($s . self::CRTL);
        }
        public function close() {
            if ($this->connected) {
                fclose($this->sock);
                $this->connected = false;
            }
        }
        private function formatTimeout($timeout, $default = null){
            $t = intval($timeout);
            if ($t <= 0) {
                if (!$default) {
                    $t = ini_get('default_socket_timeout');
                } else {
                    $t = $default;
                }
            }
            return $t;
        }
    
        private function checkReadTimeout(){
            $meta = stream_get_meta_data($this->sock);
            if (isset($meta['timed_out'])) {
                $this->close();
            }
        }
    
        private function handleReadError(){
            $this->checkReadTimeout();
            $this->close();
        }
    }
  • 相关阅读:
    利用sklearn训练LDA主题模型及调参详解
    关联规则挖掘:Apriori算法(基于Groceries数据集)
    极大连通子图与极小连通子图
    TCP协议“三次握手”与“四次挥手”详解(下)
    TCP协议“三次握手”与“四次挥手”详解(上)
    95题--不同的二叉搜索树II(java、中等难度)
    96题--不同的二叉搜索树(java、中等难度)
    CRC循环冗余校验---模2除法解析
    黑盒测试用例设计方法总结
    软件配置管理和软件维护的区别【详细】
  • 原文地址:https://www.cnblogs.com/taoshihan/p/11508391.html
Copyright © 2011-2022 走看看