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->lect('nt');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
<?phpclass sina_mail_net_imap {const max_read_size = 100000000;const pattern_request_string_quence = '/{\d+}/';const pattern_respon_string_quence = '/{(\d+)}$/';const quence_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_quence = 256;const param_arch = 512;const param_body = 1024;const param_partial = 2048;const param_exclusive = 4096;private static $statuskeywords = array('messages' => lf::param_no,'recent' => lf::param_no,'uidnext' => lf::param_no,'uidvalidity' => lf::param_no,'unen' => lf::param_no,);private static $archkeywords = array('all' => lf::param_no,'answered' => lf::param_no,'bcc' => 18, // lf::param_single | lf::param_string,'before' => 66, // lf::param_single | lf::param_date,'body' => 18, // lf::param_single | lf::param_string,'cc' => 18, // lf::param_single | lf::param_string,'deleted' => lf::param_no,'draft' => lf::param_no,'flagged' => lf::param_no,'from' => 18, // lf::param_single | lf::param_string,'header' => 20, // lf::param_pair | lf::param_string,'keyword' => 130, // lf::param_single | lf::param_flag,'larger' => 34, // lf::param_single | lf::param_number,'new' => lf::param_no,'not' => 514, // lf::param_single | lf::param_arch,'old' => lf::param_no,'on' => 66, // lf::param_single | lf::param_date,'or' => 516, // lf::param_pair | lf::param_arch,'recent' => lf::param_no,'en' => lf::param_no,'ntbefore' => 66, // lf::param_single | lf::param_date,'nton' => 66, // lf::param_single | lf::param_date,'ntsince' => 66, // lf::param_single | lf::param_date,'since' => 66, // lf::param_single | lf::param_date,'smaller' => 34, // lf::param_single | lf::param_number,'subject' => 18, // lf::param_single | lf::param_string,'text' => 18, // lf::param_single | lf::param_string,'to' => 18, // lf::param_single | lf::param_string,'uid' => 258, // lf::param_single | lf::pa感谢朋友的话ram_quence,'unanswered' => lf::param_no,'undeleted' => lf::param_no,'undraft' => lf::param_no,'unflagged' => lf::param_no,'unkeyword' => 130, // lf::param_single | lf::param_flag,'unen' => lf::param_no,);private static $fetchkeywords = array('all' => 4097, // lf::param_no | lf::param_exclusive,'fast' => 4097, // lf::param_no | lf::param_exclusive,'full' => 4097, // lf::param_no | lf::param_exclusive,'body' => 3075, // lf::param_no | lf::param_single | lf::param_body | lf::param_partial,'body.peek' => 3074, // lf::param_single | lf::param_body | lf::param_partial,'bodystructure' => lf::param_no,'envelope' => lf::param_no,'flags' => lf::param_no,'internaldate' => lf::param_no,'rfc822' => lf::param_no,'rfc822.header' => lf::param_no,'rfc822.size' => lf::param_no,'rfc822.text' => lf::param_no,'uid' => lf::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 $lastnd = '';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->getrespon();}public function capability() {$res = $this->request('capability');if (ist($res[0][0]) && $res[0][0] == '*' &&ist($res[0][1]) && strcacmp($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 (ist($this->capabilities['id'])) { $this->request('id', array($data)); } }public function login($urname, $password) {try {$this->request('login', array($urname, $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 (ist($r[0]) && $r[0] == '*' && ist($r[1]) && strcacmp($r[1], 'list') == 0 && ist($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, lf::$statuskeywords);$res = $this->request('status', array($folder, $args));$status = array();if (!empty($res)) { foreach ($res as &$r) {if (ist($r[0]) && $r[0] == '*' && ist($r[1]) && strcacmp($r[1], 'status') == 0 && ist($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 lect($folder) {$res = $this->request('lect', array($folder));$status = array();if (!empty($res)) {foreach ($res as $r) {if (ist($r[0]) && $r[0] == '*') {if (ist($r[1]) && ist($r[2])) {if (strcacmp($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];}} elif (ctype_digit($r[1])) {$status[$r[2]] = $r[1];} el {$status[$r[1]] = $r[2];} }}}}$this->currentfolder = $folder;return $status;}public function arch($data) { $args = $this->formatargsforcommand($data, lf::$archkeywords, true); $res = $this->request('arch', $args);$ls = array();foreach ($res as &$r) {if (ist($r[0]) && $r[0] == '*' && ist($r[1]) && strcacmp($r[1], 'arch') == 0) {for ($i = 2, $n = count($r); $i < $n; ++$i) {$ls[] = $r[$i];}}}return $ls;}public function fetch($q, $data) { $qstr = $this->formatquence($q); $args = $this->formatargsforcommand($data, lf::$fetchkeywords); $res = $this->request('fetch', array($qstr, $args));// var_dump($res);$ls = array();foreach ($res as &$r) {if (ist($r[0]) && $r[0] == '*' &&ist($r[1]) && is_numeric($r[1]) && ist($r[2]) && strcacmp($r[2], 'fetch') == 0 &&ist($r[3]) && is_array($r[3])) {$a = array();for ($i = 0, $n = count($r[3]); $i < $n; $i += 2) {$key = $r[3][$i];if (((strcacmp($key, 'body') == 0 && ist($args['body']) && is_array($args['body'])) || (strcacmp($key, 'body.peek') == 0 && ist($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++;} el {$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;// 格式化参数列表$strqlist = array();if (is_array($args)) {$argstr = $this->formatrequestarray($args, $strqlist); } el { $argstr = $this->formatrequeststring($args, $strqlist);}//$argstr = $this->makerequest($args, $strqlist);$subreqs = array();if (ist($argstr[0])) {$req .= ' ' . $argstr;// 如果参数中包括需要序列化的数据,根据序列化标识{length}将命令拆分成多条if (!empty($strqlist) && preg_match_all(lf::pattern_request_string_quence, $req, $matches, preg_offt_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($strqlist) + 1) {$subreqs = null;}}}if (empty($subreqs)) {// 处理单条命令$this->sock->writeline($req);$this->lastnd = $req; $res = $this->getrespon($tag);} el { // 处理多条命令$this->lastnd = '';foreach ($subreqs as $id => $req) {$this->sock->writeline($req); $this->lastnd .= $req;$res = $this->getrespon($tag); if (ist($res[0][0]) && $res[0][0] == '+') {$this->sock->write($strqlist[$id]); $this->lastnd .= "\r\n" . $strqlist[$id];} el {// 如果服务器端返回其他相应,则定制后续执行break;}} }return $res;}private function formatrequeststring($s, &$strqlist) {$s = trim($s);$needquote = fal;if (!ist($s[0])) {$needquote = true;} elif ($this->currentcommand == 'id') { $needquote = true;} el {// 参数包含多行时,需要进行序列化if (strpos($s, "\r") !== fal || strpos($s, "\n") !== fal) { $strqlist[] = $s;$s = sprintf('{%d}', strlen($s));} el {// 参数包含双引号或空格时,需要将使用双引号括起来if (strpos($s, '"') !== fal) {$s = addcslashes($s, '"');$needquote = true;}if (strpos($s, ' ') !== fal) {$needquote = true;}}}if ($needquote) {return sprintf('"%s"', $s);} el {return $s;}}private function formatrequestarray($arr, &$strqlist, $level = -1) {$a = array();foreach ($arr as $k => $v) {$isbody = fal;$supportpartial = fal;$partialstr = '';if ($this->currentcommand == 'fetch') {// 识别是否body命令,是否可以包含<partial>$kw = strtoupper($k); if (ist(lf::$fetchkeywords[$kw]) && (lf::$fetchkeywords[$kw] & lf::param_body) > 0) {$isbody = true;}if (ist(lf::$fetchkeywords[$kw]) && (lf::$fetchkeywords[$kw] & lf::param_partial) > 0) {$supportpartial = true;}} if (is_array($v)) { if ($supportpartial && ist($v[lf::partial_param_name]) && is_array($v[lf::partial_param_name])) { // 处理包含<partial>的命令foreach ($v[lf::partial_param_name] as $spos => $mlen) {$partialstr = sprintf('<%d.%d>', $spos, $mlen);} unt($v[lf::partial_param_name]);}$s = $this->formatrequestarray($v, $strqlist, $level + 1);} el {$s = $this->formatrequeststring($v, $strqlist);} if (!is_numeric($k)) {// 字典方式需要包含键名$k = $this->formatrequeststring($k, $strqlist);if ($isbody) {$s = $k . $s; } el {$s = $k . ' ' . $s;}// 包含<partial>if ($supportpartial) {$s .= $partialstr;}}$a[] = $s;}if ($level < 0) {return implode(' ', $a);} elif (($level % 2) == 0) {return sprintf('(%s)', implode(' ', $a));} el {return sprintf('[%s]', implode(' ', $a));}}private function formatquence($q) {$n = count($q);if ($n == 0) {return '1:*'; } elif ($n == 1) {if (ist($q[0])) {return strval($q[0]);} el {foreach ($q as $k => $v) {return $k . ':'goodbay . $v;}}} el {return implode(',', $q);}}private function formatargsforcommand(&$data, &$fields, $aslist = fal) {$args = array();foreach ($data as $k => $v) { if (is_numeric($k)) {// 无值参数$name = strtoupper($v);if (ist($fields[$name])) {// 对于排他性属性,直接返回if (($fields[$name] & lf::param_exclusive) > 0) {return $name;} elif (($fields[$name] & lf::param_no) > 0) { $args[] = $name;}}} elif ($k == lf::quence_param_name) {// 序列$args[] = $this->formatquence($v); } el {$name = strtoupper($k);if (ist($fields[$name])) {$paramtype = $fields[$name]; // 格式化参数类型if (($paramtype & lf::param_date) > 0) {$v = date('j-m-y', $v);} elif (($paramtype & lf::param_quence) > 0) {$v = $this->formatquence($v);} // 根据参数定义拼组参数列表if (($paramtype & lf::param_single) > 0) {// 单值参数if ($aslist) {$args[] = $name;$args[] = $v;} el {$args[$name] = $v;}} elif (($paramtype & lf::param_pair) > 0) {// 键值对参数if (is_array($v)) {foreach ($v as $x => $y) {$pk = $x;$pv = $y;break;}} el {$pk = $v;$pv = '';}if ($aslist) {$args[] = $name;$args[] = $pk;$args[] = $pv;} el {$args[$name] = array($pk => $pv);}} elif (($paramtype & lf::param_list) > 0) {// 列表参数if ($aslist) {$args[] = $name;foreach ($v as $i) {$args[] = $i;}} el {$args[$name] = $v;}} elif (($paramtype & lf::param_no) > 0) {// 无值参数$args[] = $name;}}}}return $args;}private function getrespon($tag = null) {$r = array();$readmore = true; while ($readmore) {$ln = trim($this->sock->readline()); if (!ist($ln[0])) {// connection clod or read empty string, throw exception to avoid dead loop and reconnectthrow new exception('read respon failed');}$matches = null;$strqkey = null;$strq = null;if (preg_match(lf::pattern_respon_string_quence, $ln, $matches)) {$strqkey = $matches[0];$this->readquence($ln, $strq, $matches[1]);}$this->lastrecv = $ln;// 区分处理不同种响应switch ($ln[0]) {ca '*':$r[] = $this->parline($ln, $strqkey, $strq); if (!$tag) {$readmore = fal;}break;ca $this->tagname:$r[] = $this->parline($ln);if ($tag) {$readmore = fal;} el {}break;ca '+':$r[] = $this->parline($ln);$readmore = fal;break;default:$r[] = $ln;break;} } //var_dump($this->lastnd, $this->lastrecv);// 无响应数据if (empty($r)) {throw new exception('no respon');}$last = $r[count($r) - 1];if (ist($last[0]) && $last[0] == '+') {// 继续发送请求数据} el {if ($tag) {if (!ist($last[0]) || strcacmp($last[0], $tag) != 0) { throw new exception('tag no match');} } el {if (!ist($last[0]) || strcacmp($last[0], '*') != 0) { throw new exception('untag no match');}}if记叙文阅读 (ist($last[1])) {// 处理响应出错的情况if (strcacmp($last[1], 'bad') == 0) { throw new exception(implode(' ', $last));} elif (strcacmp($last[1], 'no') == 0) {throw new exception(implode(' ', $last));}}//$this->currentcommand = null;}return $r;}private function readquence(&$ln, &$strq, $qlength) {// 对于字符串序列,读取完整内容后再拼接响应 $readlen = 0;$st = microtime(true);// 网络请求多次读取字符串序列内容,直到读好为止while ($readlen < $qlength) {$sb = $this->sock->read($qlength - $readlen);if (ist($sb[0])) {$strq .= $sb;$readlen = strlen($strq);} if ((microtime(true) - $st) > $this->timeout) {throw new exception('read quence timeout');}}// 读取字符串序列后的剩余命令$leftln = rtrim($this->sock->readline());$ln = $ln . $leftln;}private function parline($ln, $strqkey = null, $strq = null) {$r = array();$p =& $r;$stack = array();$token = '';$escape = fal;$inquote = fal;for ($i = 0, $n = strlen($ln); $i < $n; ++$i) {$ch = $ln[$i];if ($ch == '"') {// 处理双引号括起的字符串if (!$inquote) {$inquote = true;} el {$inquote = fal;}} elif ($inquote) {// 对于括起的字符串,处理双引号转义if ($ch == '\\') {if (!$escape && ist($ln[$i + 1]) && $ln[$i + 1] == '"') { $token .= '"';$i++;} el {$token .= $ch;$escape = !$escape;} } el {$token .= $ch;}} elif ($ch == ' ' || $ch == '(' || $ch == ')' || $ch == '[' || $ch == ']') {// 处理子列表if (ist($token[0])) {// 将字符串序列标识:{length},替换为真实字符串if ($strqkey && $token == $strqkey) {$p[] = $strq;} el {$p[] = $token;}$token = '';} if ($ch == '(' || $ch == '[') { $p[] = array();$stack[] =& $p;$p =& $p[count($p) - 1]; } elif ($ch == ')' || $ch == ']') { $p =& $stack[count($stack) - 青春永不言败1];array_pop($stack);}} el { // 处理字符串字面量$token .= $ch;} }if (ist($token[0])) {// 将字符串序列标识:{length},替换为真实字符串if ($strqkey && $token == $strqkey) {$p[] = $strq;} el {$p[] = $token;}}return $r;}}// end of php
socket.php
<?phpclass socket{const default_read_size = 8192;const crtl = "\r\n";private $uri = null;private $timeout = null;private $sock = null;private $connected = fal;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->clo();}$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_t_timeout($this->sock, $this->timeout);$this->connected = true;}public function read($size){asrt($this->connected);$buf = fread($this->sock, $size);if ($buf === fal) {$this->handlereaderror();}return $buf;}public function readline(){asrt($this->connected);$buf = '';while (true) {$s = fgets($this->sock, lf::default_read_size);if ($s === fal) {$this->checkreadtimeout();break;}$n = strlen($s);if (!$n) {break;}$buf .= $s;if ($s[$n - 1] == "\n") {break;}}return $buf;}public function readall(){asrt($this->connected);$buf = '';while (true) {$s = fread($this->sock, lf::default_read_size);if ($s === fal) {$this->handlereaderror();}if (!ist($s[0])) {break;}$buf .= $s;}return $buf;}public function write($s){asrt($this->connected);$n = strlen($s);$w = 0;while ($w < $n) {$buf = substr($s, $w, lf::default_read_size);$r = fwrite($this->sock, $buf);if (!$r) {$this->clo();}$w += $r;}}public function writeline($s){$this->write($s . lf::crtl);}public function clo() {if ($this->connected) {fclo($this->sock);$this->connected = fal;}}private function formattimeout($timeout, $default = null){$t = intval($timeout);if ($t <= 0) {if (!$default) {$t = ini_get('default_socket_timeout');} el {$t = $default;}}return $t;}private function checkreadtimeout(){$meta = stream_get_meta_data($this->sock);if (ist($meta['timed_out'])) {$this->clo();}}private function handlereaderror(){$this->checkreadtimeout();$this->clo();}}
本文发布于:2023-04-07 16:27:48,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/921b48b522e2f5b38dc67badad84e47e.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:[PHP] PHP调用IMAP协议读取邮件类库.doc
本文 PDF 下载地址:[PHP] PHP调用IMAP协议读取邮件类库.pdf
留言与评论(共有 0 条评论) |