作者 邓超

1

... ... @@ -4,74 +4,136 @@
use Swoole\Process;
include_once __DIR__."/config.php";
include_once __DIR__."/function.php";
include_once __DIR__."/../vendor/autoload.php";
function start(){
// 启动一个进程池进行管理
// 删除停止运行的值
redis()->delete(RUNNING_REDIS_KEY);
/** 创建一个表 **/
$table = new Swoole\Table(128);// 128 行
$table->column('val', Swoole\Table::TYPE_INT);
$table->create();
// 初始时,进行一次统计
$table->set('etotal',['val'=> db()->count(\Model\email::count())]);
// 启动一个进程池进行管理
$topPool = new Process\Pool(WORKER_NUM);
// 每10分钟统计一次邮箱数量
$timer_id = \Swoole\Timer::tick(600,function () use (&$table){
$table->set('etotal',['val'=> db()->count(\Model\email::count())]);
});
// 每2秒执行一次
$timer_check_id = \Swoole\Timer::tick(2,function () use (&$table,$topPool){
// 是否停止脚本
$table->set('stop',['val'=> redis()->get(RUNNING_REDIS_KEY) === 'stop' ? 1 : 0]);
// 检查是否结束了所有的协程同步代码
if ($table->get('stop','val')) {
$stop_num = 0;
foreach (range(0, WORKER_NUM) as $i) {
if ($table->exists('ps' . $i)) {
$stop_num++;
}
}
if($stop_num >= WORKER_NUM){
// 退出进程
$topPool->shutdown();
}
}
// 邮件总数
$total = redis()->get('email_total',0);
if($total > $table->get('etotal','val')){
$table->set('etotal',['val'=> $total]);
}
});
// 这个是启用协程
$topPool->set(['enable_coroutine' => true]);
// 协程配置
\co::set([
'max_coroutine'=>1000, // 最大携程数量
'max_coroutine'=>COROUTINE_MAX_NUM, // 最大携程数量
'hook_flags'=>SWOOLE_HOOK_TCP, // redis需要的配置
]);
// 开始工作
$topPool->on('WorkerStart',function (Process\Pool $pool,$worker_id){
$topPool->on('WorkerStart',function (Process\Pool $pool,$worker_id) use (&$table){
_echo("进程({$worker_id})启动成功");
// 是否停止,这里进行阻塞
if ($table->get('stop','val')){
// 某个进程退出了
$table->set('ps'.$worker_id,['val'=>1]);
co::sleep(1);
return true;
}
// 协程id集
$cid = [];
// 删除停止运行的值
swoole_redis()->delete(RUNNING_REDIS_KEY);
// \Co\run(function (){
// 开启多个协程
foreach (range(1,COROUTINE_NUM) as $i){
go(function () use ($cid,$worker_id){
// 协程id
$cid[co::getCid()] = co::getCid();
$redis = swoole_redis();
// 同步操作
while (true){
// 开始同步
try {
sync();
}catch (Throwable $e){
logs($e->getMessage(),LOG_PATH.'/'.$worker_id.'_'.co::getCid().'.log');
}
// 是否停止
if($redis->get(RUNNING_REDIS_KEY) == 'stop'){
break;
}
// 阻塞1秒
co::sleep(1);
}
// 协程完成后执行的函数
co::defer(function () use ($cid){
_echo('正常关闭协程('.co::getCid().')');
unset($cid[co::getCid()]);
});
});
}
// });
$i = 0;
$email_total = $table->get('etotal','val');//邮件总数量
$isRunMaxCNum = 1; // 允许最大协程数量,如果为0则停止所有协程工作,相当于停止脚本
// 是否退出进程
while (true){
if($cid){
co::sleep(1);
}else{
$i++;
// 每10秒 验证一次邮箱数量,好控制协程的数量
if($i>=10){
$email_total = $table->get('etotal','val');
$i = 0;
}
if(!$email_total){
break;
}
// 每个协程 分配 10个邮箱任务
$cnum = ceil($email_total/40);
// 当前协程的数量
$nowCnum = count($cid);
// 说明 需要新的协程了
if($cnum > $nowCnum){
// 开启所需要的协程数量
foreach (range(0,$cnum-$nowCnum) as $v){
// 启动一个协程
create_coroutine($cid,$isRunMaxCNum,$worker_id);
}
}
// 暂时没有实现 减少协程数量操作
// else if ($cnum < $nowCnum){
// // 说明 协程数量过多,小于了1个协程处理10个邮箱的,资源闲置情况
// // 销毁多余协程
// $isRunMaxCNum = $nowCnum - $cnum;
// }
// 每3秒检查一次是否要停止 协程
if($i%3 === 0){
// _echo('是否收到退出信号:'.$table->get('stop','val'));
if ($table->get('stop','val')){
// 停止
$isRunMaxCNum = 0;
}
}
// 这个是检查 cid的如果协程全部退出,则退出进程
co::sleep(1);
// 跳出无限循环了
if(!$cid){
_echo('正常关闭进程('.$worker_id.')');
// 关闭当前进程
$pool->shutdown();
// $pool->shutdown();
break;
}
}
... ... @@ -87,12 +149,55 @@ function start(){
}
/**
* 创建协程
* @param array $cid
* @param int $isRunMaxCNum
* @param $worker_id
* @author:dc
* @time 2023/2/14 17:04
*/
function create_coroutine(array &$cid,int &$isRunMaxCNum,$worker_id){
go(function () use (&$cid,&$isRunMaxCNum,$worker_id){
// 协程id
$cid[co::getCid()] = co::getCid();
// 同步操作
while (true){
// 是否退出协程
if(!$isRunMaxCNum){
_echo('协程('.co::getCid().'): stop '.$isRunMaxCNum);
break;
}
// 开始同步
try {
sync();
}catch (\Throwable $e){
_echo($e->getMessage());
logs($e->getMessage().PHP_EOL.$e->getTraceAsString(),LOG_PATH.'/'.$worker_id.'_'.co::getCid().'.log');
}
// 阻塞1秒
co::sleep(1);
}
// 协程完成后执行的函数
co::defer(function () use (&$cid){
_echo('正常关闭协程('.co::getCid().')');
unset($cid[co::getCid()]);
});
});
}
/**
* 开始同步
* @author:dc
* @time 2023/2/13 9:42
*/
function sync(){
db()->first();
co::sleep(1);
}
... ... @@ -106,7 +211,7 @@ switch ($argv[1]){
case 'stop':{
\Co\run(function (){
echo "正在退出程序...\n";
swoole_redis()->set(RUNNING_REDIS_KEY,'stop');
redis()->set(RUNNING_REDIS_KEY,'stop');
while (true){
$num = exec("ps -ef | grep \"sync_email.php start\" | grep -v grep | wc -l");
if(!$num){
... ... @@ -128,7 +233,6 @@ switch ($argv[1]){
}
}
exit();
... ...
... ... @@ -6,6 +6,7 @@
"require": {
"php": "^8.0.2",
"ext-pdo": "*",
"ext-redis": "*",
"phpmailer/phpmailer": "^6.7"
},
"require-dev": {
... ...
... ... @@ -4,8 +4,8 @@ error_reporting(E_ERROR | E_NOTICE);
// 开启4个进程
define('WORKER_NUM',4);
// 开启100个协程
define('COROUTINE_NUM',100);
// 开启最大1000个协程
define('COROUTINE_MAX_NUM',1000);
// 是否继续运行
define('RUNNING_REDIS_KEY','worker_is_running');
// 记录日志的目录
... ...
... ... @@ -37,8 +37,13 @@ class Home {
app()->e('smtp_verify_error');
}
// 进行远程登录,验证
// 查询数据
$model = db()->first(\Model\email::first($formData['email']));
if(!$model){
$model = new Email();
$model->email = $formData['email'];
... ...
... ... @@ -105,6 +105,23 @@ class DbPool {
}
/**
* 统计数量
* @param string $sql
* @return int
* @author:dc
* @time 2023/2/14 16:19
*/
public function count(string $sql):int{
$query = $this->client->prepare($sql);
if($query->execute()){
return $query->fetch(\PDO::FETCH_COLUMN);
}
return 0;
}
/**
* 查询一条数据
... ...
<?php
namespace Helper\Mail;
use Helper\Mail\MailFun;
/**
* 解析邮件body内容
* 通过 fetch msgno RFC822.text 获取到的内容
* 此内容包含html 文本 附件
* @author:dc
* @time 2022/8/12 9:15
* Class Body
* @package App\Mail\lib
*/
class Body {
/**
* @var string
*/
private $body;
/**
*
* @var array
*/
private $item = [];
/**
* 保存的目录
* @var string
*/
private $fileSavePath;
/**
* Body constructor.
* @param string $body
* @param string $fileSavePath
*/
public function __construct(string $body, string $fileSavePath='/')
{
$this->body = $body = trim($body);
$this->fileSavePath = $fileSavePath;
// 这个是描述特殊文本
if(strpos($body,'This is a multi-part message in MIME format.')===0){
$body = trim($body,'This is a multi-part message in MIME format.');
$body = trim($body);
}
// 163 有
if(strpos($body,'------=_Part')!==false){
$this->parse($body,'------=_Part');
}
elseif (mb_strpos($body,'------=_NextPart')!==false){
$this->parse($body,'------=_NextPart');
}
elseif (mb_strpos($body,'----_NmP')!==false){
$this->parse($body,'----_NmP');
}
elseif (mb_strpos($body,'--_=_swift')!==false){
$this->parse($body,'--_=_swift');
}
elseif (mb_strpos($body,'----==_mimepart')!==false){
$this->parse($body,'----==_mimepart');
}
elseif (mb_strpos($body,'--------------Boundary')!==false){
$this->parse($body,'--------------Boundary');
}
elseif (mb_strpos($body,'--=-')!==false){
$this->parse($body,'--=-');
}
// 很多--开始的,且不规则
elseif(strpos($body,'--')===0){
// 获取第一行
$tag = $this->body_get_tag($body,'--');
// 以第一行为标准
$this->parse($body,trim($tag));
}
// 直接html
elseif (mb_strpos($body,'<')===0){
$body = quoted_printable_decode($body);
// preg_match("/<meta(?!\s*(?:name|value)\s*=)(?:[^>]*?content\s*=[\s\"']*)?([^>]*?)[\s\"';]*charset\s*=[\s\"']*([^\s\"'\/>]*)/",$body,$icon);
// if(!empty($icon[2])){
// // 解码
// $body = mb_convert_encoding($body,'utf-8',$icon[2]);
// }
$this->setItem(['type'=>'text/html','body'=>$body]);
}
else{
// qq的是base64
if(rtrim($body,'=') == rtrim(base64_encode(base64_decode($body)),'=')){
$this->setItem(['type'=>'text/plain','body'=>base64_decode($body)]);
}else{
$this->setItem(['type'=>'text/plain','body'=>$body]);
}
}
}
/**
* 获取标签
* @param $body
* @param $tag
* @return mixed|string
* @author:dc
* @time 2022/8/12 10:49
*/
private function body_get_tag($body,$tag){
preg_match("/{$tag}[\w\W].*/i",$body,$result);
if(!empty($result[0])) {
return $result[0];
}
return '';
}
/**
* @param $item
*/
private function setItem($item): void
{
$this->item[] = $item;
}
/**
* @return []
*/
public function getItem(): array
{
return $this->item;
}
/**
* 开始解析
* @param string $body
* @param string $tag
* @return array
* @author:dc
* @time 2022/8/12 9:50
*/
private function parse(string $body, string $tag){
// 删除第一个标签前面的数据,一般情况无用
$body = mb_substr($this->body,strpos($this->body,$tag),99999999999);
// 有附件的情况
preg_match('/boundary="([-_A-Za-z0-9=\.]{1,})"/i',$body,$boundary);
if($boundary[0]??''){
$body = str_replace($boundary[0],'',$body);
// $body = mb_substr($body,mb_strpos($body,$boundary[0])+strlen($boundary[0]),99999999999);
}
// 附件情况
if(!empty($boundary[1])){
preg_match_all('/.*'.$boundary[1].'.*/i',$body,$boundary_tag);
$body = str_replace($boundary_tag[0],'{--tag--}',$body);
}
// 查找tag块
preg_match_all("/(".$tag.".*+\n)/i",$body."\r\n\r\n",$he);
// 把每个tag块分开成数组
if(!empty($he[0])){
foreach ($he[0] as $hk=>$h){
$he[0][$hk] = trim($h);
}
arsort($he[0]);
$body = str_replace($he[0],'{--tag--}',$body);
}
$body = explode('{--tag--}',$body);
// 处理
foreach ($body as $key=>$item){
$data = [];
$item = trim($item);
// 附件的头
if(!$item) { continue; }
// 邮件体包含邮件体
if(preg_match("/boundary=\"([-_a-z0-9]{5,})\"/Ui",$item,$bm)){
if (strpos($item,$bm[1].'--')!==false){
$data = (new self('--'.$bm[1]."\r\n".$item,$this->fileSavePath))->getItem();
// $this->setItem($data);
// 合并邮件体
$this->item = array_merge($this->item,$data);
}
continue;
}
// 先解码解码
$encode = $this->body_match_tag('Content-Transfer-Encoding:',$item);
if($encode){
$data['encode'] = strtolower($encode['text']);
$item = str_replace($encode['origin'],'',$item);
}
// 内容类型
$type = $this->preg_match_type($item);
if($type){
$data['type'] = strtolower($type['type']);
// 编码
if(isset($type['charset'])){
$data['charset'] = strtolower($type['charset']);
}
// nama。附件
if(isset($type['name'])){
$data['name'] = $type['name'];
}
// 删除
$item = str_replace($type['origin'],'',$item);
}
//
if(empty($data['charset'])){
// 编码
$code = $this->preg_match_charset($item);
if($code){
$data['charset'] = strtolower($code['charset']);
$item = str_replace($code['origin'],'',$item);
}
}
// 先匹配留存文件名称
preg_match('/filename="(\w?.*)"/',$item,$filename);
if(!empty($filename[1])){
$filename = MailFun::decodeMimeStr($filename[1]);
}
// 删除不需要的tag属性,如果需要进进行解析
$item = $this->body_remove_tag($item,'Content-Description:');
$item = $this->body_remove_tag($item,'Content-Disposition:');
$item = $this->body_remove_tag($item,'Mime-Version:');
$data['body'] = trim($item);
if(!empty($data['type'])){
// 邮件头
if($data['type'] == 'multipart/alternative'){
}
// 是文本还是附件
else if(strpos($data['type'],'text/') === 0 ){
// body解密
switch($data['encode']??''){
case 'base64': {
$data['body'] = base64_decode($data['body']);
break;
}
case 'quoted-printable': {
$data['body'] = quoted_printable_decode($data['body']);
break;
}
case '8bit': {
try {
$data['body'] = DeCoding::de8bit($data['body']);
$data['body'] = quoted_printable_decode($data['body']);
}catch (\Throwable $e){
}
break;
}
}
// 转码
// if(isset($data['charset']) && $data['charset']){
// $debody = @mb_convert_encoding($data['body'],'utf-8',$data['charset']);
// if($debody){
// $data['body'] = $debody;
// $debody = null;
// }
// }
}
// 系统退信//里面包含了发送邮件所有内容,这里不记录
elseif (strpos($data['type'],'message') === 0){
$data['body'] = '';// 一般不需要这些内容,如有需要就要重新解析
}
elseif (!empty($data['type']) && $data['body']){
// 解析附件
$data = $this->parseFile($data,$filename);
}
}
$this->setItem($data);
}
}
/**
* 解析文件
* @param $item
* @return array|mixed
* @author:dc
* @time 2022/8/12 10:40
*/
private function parseFile($item,$filename=''){
$data = [];
// 查找文件名
$data['filename'] = $this->file_save_name($item['body'],'filename');
$data['name'] = $this->file_save_name($item['body'],'name');
$data['name'] = $data['name'] ? : ($item['name']??$filename);
$data['filename'] = $data['filename'] ? : $data['name'];
// 是否有文件名
if(empty($data['filename']) || strpos($data['filename'],'.')===false){
return $item;
}
$ext = explode('.',$data['filename']);
$ext = end($ext);
// if(!empty($item['type'])){
// // 文件类型来判断后缀
// // // download it from http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
// if(is_readable(__DIR__.'/mime.types')){
// $f = fopen(__DIR__.'/mime.types','r');
// while(!feof($f)){
// $fext = fgets($f);
// if($fext){
// $fext = strtolower($fext);
// $item['type'] = strtolower($item['type']);
// // 找到了类型后缀
// if(strpos($fext,$item['type']) === 0){
// $ext = trim(str_replace($item['type'],'',$fext));
// break;//找到了要跳出循环
// }
// }
// }
// // 关闭文件
// fclose($f);
// }
// }
// 找不到后缀,说明不是文件
// if(empty($ext)){
// 文件后缀
// $ext = explode('.',$data['filename']);
// $ext = count($ext) > 1 ? ($ext[count($ext)-1]??'') : '';
// 直接返回
// return $item['body'];
// }
// content id
preg_match("/Content-ID:[\s].*<[\w\W]{1,}>/i",$item['body'],$result);
if (!empty($result[0])){
$data['content-id'] = explode('<',$result[0]);
$data['content-id'] = $data['content-id'][1];
$data['content-id'] = trim($data['content-id']);
$data['content-id'] = trim($data['content-id'],'>');
$item['body'] = str_replace($result[0],'',$item['body']);
}
$item['body'] = str_replace($result,'',$item['body']);
$content = base64_decode(trim($item['body']));
if($content){
// 目录
$data['path'] = $this->fileSavePath;
if(!is_dir($data['path'])){
mkdir($data['path'],0775,true);
}
$data['signName'] = md5($content).($ext ? '.'.$ext : '');
$data['path'] = $data['path'].'/'.$data['signName'];
// 保存文件
@file_put_contents($data['path'],$content);
}
return $data;
}
// 获取文件名称
private function file_save_name(&$body,$tag){
preg_match('/'.$tag.'="[(\S\W.*\s.*)]{1,}"/i',$body,$result);
if($result[0]??''){
$body = str_replace($result[0],'',$body);
}
$val = trim(str_replace([$tag.'=','"',"'"],'',$result[0]??''));
if ($val && strpos($val,'=?')===0){
$val = iconv_mime_decode($val,ICONV_MIME_DECODE_CONTINUE_ON_ERROR,'utf-8');
}
return $val;
}
/**
* 删除tag
* @param $body
* @param $tag
* @return mixed|string|string[]
* @author:dc
* @time 2022/8/12 10:34
*/
private function body_remove_tag($body,$tag){
preg_match("/{$tag}[\w\W].*/i",$body,$result);
if(!empty($result[0])) {
$body = str_replace($result, '', $body);
}
return $body;
}
/**
* 读取编码
* @param $item
* @return array
* @author:dc
* @time 2022/8/12 10:28
*/
private static function preg_match_charset($item){
// 匹配内容 type
preg_match('/charset[ \t]{0,}=[ \t]{0,}"?[ \t0-9a-zA-Z-]{1,}"?/i',$item,$result);
if(!empty($result[0])){
$ret['origin'] = trim($result[0]);
// charset
$ret['charset'] = trim(str_replace(['charset','=','"',"'"],'',$ret['origin']));
return $ret;
}
return [];
}
/**
* 解析type
* @param $item
* @return array
* @author:dc
* @time 2022/8/12 10:26
*/
private function preg_match_type($item){
// 匹配内容 type
preg_match("/Content-Type:[\w\W].*/i",$item,$result);
if(!empty($result[0])){
$ret['origin'] = trim($result[0]);
// type
$type = str_replace(['Content-Type:','"',"'"],'',$ret['origin']);
$type = explode(';',$type);
// 类型
$ret['type'] = trim($type[0]);
if(isset($type[1]) && $type[1]){
// 编码
$r = explode('=',$type[1]);
$ret[strtolower(trim($r[0]))] = trim($r[1]??'');
}
return $ret;
}
return [];
}
/**
* 匹配tag
* @param $tag
* @param $item
* @return array
* @author:dc
* @time 2022/8/12 10:05
*/
private function body_match_tag($tag,$item){
// tag Content-Transfer-Encoding:
preg_match("/".$tag."[\w\W].*/i",$item,$result);
if(!empty($result[0])){
$ret['origin'] = trim($result[0]);
// charset
$ret['text'] = trim(str_replace([$tag,'"',"'"],'',$ret['origin']));
return $ret;
}
return [];
}
}
... ...
<?php
namespace Helper\Mail;
/**
* 解码邮件内容
* @author:dc
* @time 2022/8/12 9:33
* Class DeCoding
* @package App\Mail\lib\MailParse
*/
class DeCoding {
/**
* @param $sText
* @param bool $bEmulate_imap_8bit
* @return string
* @author:dc
* @time 2022/8/12 9:34
*/
public static function de8bit($sText,$bEmulate_imap_8bit=true) {
// split text into lines
$aLines=explode(chr(13).chr(10),$sText);
for ($i=0;$i<count($aLines);$i++) {
$sLine =& $aLines[$i];
if (strlen($sLine)===0) continue; // do nothing, if empty
$sRegExp = '/[^\x09\x20\x21-\x3C\x3E-\x7E]/e';
// imap_8bit encodes x09 everywhere, not only at lineends,
// for EBCDIC safeness encode !"#$@[\]^`{|}~,
// for complete safeness encode every character :)
if ($bEmulate_imap_8bit)
$sRegExp = '/[^\x20\x21-\x3C\x3E-\x7E]/e';
$sReplmt = 'sprintf( "=%02X", ord ( "$0" ) ) ;';
$sLine = preg_replace( $sRegExp, $sReplmt, $sLine );
// encode x09,x20 at lineends
{
$iLength = strlen($sLine);
$iLastChar = ord($sLine{$iLength-1});
// !!!!!!!!
// imap_8_bit does not encode x20 at the very end of a text,
// here is, where I don't agree with imap_8_bit,
// please correct me, if I'm wrong,
// or comment next line for RFC2045 conformance, if you like
if (!($bEmulate_imap_8bit && ($i==count($aLines)-1)))
if (($iLastChar==0x09)||($iLastChar==0x20)) {
$sLine{$iLength-1}='=';
$sLine .= ($iLastChar==0x09)?'09':'20';
}
} // imap_8bit encodes x20 before chr(13), too
// although IMHO not requested by RFC2045, why not do it safer :)
// and why not encode any x20 around chr(10) or chr(13)
if ($bEmulate_imap_8bit) {
$sLine=str_replace(' =0D','=20=0D',$sLine);
//$sLine=str_replace(' =0A','=20=0A',$sLine);
//$sLine=str_replace('=0D ','=0D=20',$sLine);
//$sLine=str_replace('=0A ','=0A=20',$sLine);
}
// finally split into softlines no longer than 76 chars,
// for even more safeness one could encode x09,x20
// at the very first character of the line
// and after soft linebreaks, as well,
// but this wouldn't be caught by such an easy RegExp
preg_match_all( '/.{1,73}([^=]{0,2})?/', $sLine, $aMatch );
$sLine = implode( '=' . chr(13).chr(10), $aMatch[0] ); // add soft crlf's
}
// join lines into text
return implode(chr(13).chr(10),$aLines);
}
}
... ...
<?php
declare(strict_types=1);
namespace Helper\Mail;
use Helper\Mail\Body;
/**
* imap协议直连服务器无需 imap扩展
* @time 2022/8/5 14:17
* Class Imap
* @package App\Mail\lib\socket
*/
class Imap {
/**
* @var resource
*/
private $socket;
/**
* ssl://imap.qq.com:993
* @var string
*/
private $host;
/** 邮箱
* @var
*/
private $username;
/**
* 邮箱密码,单独设置的imap密码
* @var
*/
private $password;
/**
* 请求时增加的tag
* @var int
*/
private $tagNum = 0;
/**
* 标签名称
* @var string
*/
private $tagName = 'A';
/**
* imap服务器设置id 邮箱邮件服务器是必须的
* @var string[]
*/
private $imapId = [
'name' => 'global so Client',
'version' => '1',
'os' => 'global so',
'os-version' => '1.0'
];
/**
* 用户的id,email表
* @var int
*/
public $id = 0;
/**
* 超时时间
* @var int
*/
private $timeout = 30;
/**
* 搜索字段,标题,邮件主题
*/
const SEARCH_FILED_SUBJECT = 'SUBJECT';
/**
* 搜索字段,发件人
*/
const SEARCH_FILED_FROM = 'FROM';
/**
* 搜索字段,收件人
*/
const SEARCH_FILED_TO = 'TO';
// const SEARCH_FILED_SUBJECT = 'RFC822.TEXT';
/**
* 邮件便签
* @var string[]
*/
public $flags = [
'SEEN' => '\\Seen', // 已读
'DELETED' => '\\Deleted', //删除
'ANSWERED' => '\\Answered',//已回复
'DRAFT' => '\\Draft',//草稿
'FLAGGED' => '\\Flagged',//星标
'FORWARDED' => '$Forwarded',
'MDNSENT' => '$MDNSent',
'*' => '\\*',
];
/**
* 已读 标记
*/
const FLAGS_SEEN = 'SEEN';
/**
* 删除 标记
*/
const FLAGS_DELETED = 'DELETED';
/**
* 已回复 标记
*/
const FLAGS_ANSWERED = 'ANSWERED';
/**
* 草稿 标记
*/
const FLAGS_DRAFT = 'DRAFT';
/**
* 星标 标记
*/
const FLAGS_FLAGGED = 'FLAGGED';
/**
* 添加邮件标签
*/
const FLAGS_APPEND = '+';
/**
* 删除邮件标签
*/
const FLAGS_REMOVE = '-';
/**
* 是否自动关闭
* @var bool
*/
private $auto_colse = true;
/**
* 调试模式
* @var bool
*/
private $debug = false;
/**
* 调试,记录日志的目录
* @var string
*/
private $debugWritePath = '';
/**
* 登录imap服务器
* @param string $host ssl://imap.qq.com:993 imap.qq.com:143
* @param string $username 邮箱地址 xxxxx@xx.com
* @param string $password 密码,此密码非邮箱登录密码,是imap服务器单独设置的密码
* @param bool $readOnly 是否以只读模式打开邮箱
* @return bool
* @throws \Exception
* @author:dc
* @time 2022/11/25 11:06
*/
public function login(string $host,string $username,string $password,bool $readOnly=false){
$this->host = $host;
$this->username = $username;
$this->password = $password;
// 查看服务器所支持的功能列表
// $this->request('CAPABILITY');
// 设置id,必须在登录前,163是强制的
$strId = '';
foreach ($this->imapId as $k=>$str){
if(!is_array($str)){
$strId .= '"'.str_replace(['"',"'"],'',$k).'" "'.str_replace(['"',"'"],'',$str).'" ';
}
}
// "name" "测试本地 Client" "version" "1" "os" "测试本地" "os-version" "1.0"
$this->request('ID ('.trim($strId).')');// 这里就不处理命令返回的信箱了
// 登录
$result = $this->request("LOGIN {$username} {$password}");
//解析登录数据每个服务商返回的登录结果不一样,很难兼容
if($result[0] != 'ok'){
throw new \Exception('IMAP Login Error:'.end($result[1]));
}
// 是否是只读模式
// 只读模式不可操作邮箱任何内容,只可查看
if($readOnly){
$this->request('EXAMINE '.$username);
}
return true;
}
/**
* email表的id
* @return int
* @author:dc
* @time 2023/2/5 11:13
*/
public function getId(){
return $this->id;
}
/**
* 设置id
* @param int $id
* @author:dc
* @time 2023/2/5 11:16
*/
public function setId(int $id){
$this->id = $id;
}
/**
* 退出当前操作的邮箱
* 一般情况不需要
* @return bool
* @throws \Exception
* @author:dc
* @time 2022/11/25 10:46
*/
public function loginOut():bool {
return $this->request('LOGOUT')[0] == 'ok';
}
/**
* @param resource $socket
*/
public function setSocket($socket,$auto_colse=true): void
{
$this->socket = $socket;
// 是否自动关闭
$this->auto_colse = $auto_colse;
}
/**
* 删除带有delete标签的邮件,删除的邮件不可恢复。
* 类似清空
* @return bool
* @throws \Exception
* @author:dc
* @time 2022/11/25 10:55
*/
public function clearDelete():bool {
return $this->request('EXPUNGE')[0] == 'ok';
}
/**
* [
[EXISTS] => 67 总邮件数
[RECENT] => 1 最新的邮件
[UIDVALIDITY] => 1
[FLAGS] => Array 此文件夹可以操控的标签
(
[0] => \Answered 回复
[1] => \Seen 已读
[2] => \Deleted 删除
[3] => \Draft 草稿
[4] => \Flagged 星标
)
[PERMANENTFLAGS] => Array
(
[0] => \Answered
[1] => \Seen
[2] => \Deleted
[3] => \Draft
[4] => \Flagged
)
]
* 选择文件夹
* @param string $folder
* @return array
* @throws \Exception
* @author:dc
* @time 2022/11/22 16:28
*/
public function selectFolder($folder='INBOX'){
// 选择文件夹
$result = $this->request("SELECT \"{$folder}\"");
if($result[0] != 'ok'){
throw new \Exception('select folder error:'.end($result[1]));
}
$list = [];
foreach ($result[1] as $item){
$item = trim($item);
// 总数量
if(preg_match("/^\* (\d+) EXISTS$/i",$item,$m)){
$list['EXISTS'] = $m[1];
}
// 最近的
elseif (preg_match("/^\* (\d+) RECENT$/i",$item,$m)){
$list['RECENT'] = $m[1];
}
// 未读
elseif (preg_match("/^\*.*\[UNSEEN (\d+)\]/i",$item,$m)){
$list['UNSEEN'] = $m[1];
}
// tag
elseif (preg_match("/^\* FLAGS \((.*)\)$/i",$item,$m)){
$list['FLAGS'] = explode(' ',$m[1]);
}
// 其他
elseif (preg_match("/^\*.*\[(.*)\]/i",$item,$m)){
// 是否有(),有小扩号就是数组
// * OK [PERMANENTFLAGS (\* \Answered \Flagged \Deleted \Draft \Seen)] Permanent flags
if(preg_match("/\((.*)\)/i",$item,$m2)){
$em = explode(' ',$m[1]);
$list[$em[0]] = explode(' ',$m2[1]);
}else{
$em = explode(' ',$m[1]);
$list[$em[0]] = $em[1];
}
}
}
return $list;
}
/**
* 关闭当前打开的文件夹,
* 使用selectFolder后才可以使用此函数
* @return bool
* @throws \Exception
* @author:dc
* @time 2022/11/25 10:40
*/
public function closeFolder():bool{
return $this->request('CLOSE')['0'] == 'ok';
}
/**
* 搜索邮件,如果要获得列表,需要配合fetch使用
* @param array $criteria 搜索[key=>value,...]
* @param bool $return_uid 是否返回uid,默认返回邮件编号
* @return array 返回的是搜索出来的uid,每个文件夹下面uid是唯一的
* @throws \Exception
* @author:dc
* @time 2022/11/24 15:46
*/
public function search(array $criteria,$return_uid = false):array{
// 命令,是否返回uid
$cmd = ($return_uid ? 'UID ' : '').'SEARCH';
foreach ($criteria as $k=>$v){
$v = addslashes($v);
$cmd .= " {$k} \"{$v}\"";
}
// 获取搜索到的 uid
$result = $this->request($cmd);
if($result[0] != 'ok'){
throw new \Exception('search error:'.end($result[1]));
}
$uids = [];
foreach ($result[1] as $item){
// 匹配uid
if(preg_match("/^\* SEARCH ([0-9\s]{1,})$/i",$item,$m)){
$uids = array_merge($uids,explode(' ',$m[1]));
}
}
return $uids;
}
/**
* 设置标签,删除标签
* @param string|int|array $data 邮件的编号或者uid
* @param array $flag 标记属性 [Imap::FLAGS_SEEN,..]
* @param string $mod 删除或者添加 Imap::FLAGS_APPEND|Imap::FLAGS_REMOVE
* @param bool $is_uid 是否使用uid进行标记
* @return bool
* @throws \Exception
* @author:dc
* @time 2022/11/24 16:58
*/
public function flags($data,array $flag,string $mod = self::FLAGS_APPEND,bool $is_uid = false):bool {
if(is_array($data)){
$data = implode(',',$data);
}
// flags 标记
foreach ($flag as $k=>$item){
if(!isset($this->flags[$item])){
unset($flag[$k]);
}else{
$flag[$k] = $this->flags[$item];
}
}
// 是否是规定中的值
if(!in_array($mod,[self::FLAGS_APPEND,self::FLAGS_REMOVE])){
throw new \Exception('set flags error: mod');
}
// 请求标记
$result = $this->request(($is_uid?'UID ':'')."STORE {$data} {$mod}FLAGS.SILENT (".implode(' ',$flag).")");
return $result[0] == 'ok';
}
/**
* 获取邮箱所有文件夹
* @return array
* @throws \Exception
* @author:dc
* @time 2022/11/24 17:20
*/
public function getFolder():array {
// 获取数据
$result = $this->request('LIST "" *');
$folder = [];
foreach ($result[1] as $item){
// 解析源数据
if(preg_match('/^\* LIST \(([\\a-z\s]{0,})\) "(.*)" "(.*)"/Ui',$item,$m)){
$folder[] = [
'parent' => $m[2],
// 源文件夹名称,在进行 select的时候必须用未解析的文件夹名称
'folder' => $m[3],
// 解析过的文件夹名称
'parseFolder' => mb_convert_encoding($m[3], 'UTF-8', 'UTF7-IMAP'),
// 是否可选择
'isSelect' => strpos($m[1],'NoSelect')===false,
];
}
}
return $folder;
}
/**
* 创建文件夹
* $folder 目录 创建二级目录用/ a/b
* @param string $folder
* @return bool
* @throws \Exception
* @author:dc
* @time 2022/11/24 23:35
*/
public function folderCreate(string $folder):bool {
// 需要转码
$folder = mb_convert_encoding($folder,'UTF7-IMAP','UTF-8');
// A003 CREATE owatagusiam 顶级
// A003 CREATE owatagusiam/owatagusiam2 有上下级关系的文件夹
$res = $this->request('CREATE '.$folder);
if ($res[0] == 'ok'){
return true;
}
throw new \Exception('create folder error:'.end($res[1]));
}
/**
* 修改文件夹名称
* @param string $oldFolder 久文件夹名称
* @param string $newFolder 新文件夹名称
* @return bool
* @throws \Exception
* @author:dc
* @time 2022/11/25 10:24
*/
public function folderRename(string $oldFolder, string $newFolder){
// 需要转码
$newFolder = mb_convert_encoding($newFolder,'UTF7-IMAP','UTF-8');
// RENAME oldfolder newfolder
$res = $this->request("RENAME {$oldFolder} {$newFolder}");
if ($res[0] == 'ok'){
return true;
}
throw new \Exception('rename folder error:'.end($res[1]));
}
/**
* 删除文件夹
* @param string $folder
* @return bool
* @throws \Exception
* @author:dc
* @time 2022/11/25 10:25
*/
public function folderDelete(string $folder):bool{
// A683 DELETE blurdybloop/test
$res = $this->request('DELETE '.$folder);
if ($res[0] == 'ok'){
return true;
}
throw new \Exception('rename folder error:'.end($res[1]));
}
/**
* 获取邮件头,并解析
* @param $data
* @param false $is_uid
* @return array
* @throws \Exception
* @author:dc
* @time 2022/11/23 14:25
*/
public function fetchHeader($data,$is_uid = false){
$result = $this->fetch($data,'header',$is_uid);
// 解析header字段
foreach ($result as $key=>$item){
$result[$key]['HEADER.FIELDS'] = $this->parseHeader($item['HEADER.FIELDS']);
}
return $result;
}
/**
* 解析header字段
* @param $header
* @return array
* @author:dc
* @time 2022/11/23 14:54
*/
public function parseHeader($header){
/****** 把数据中的 : 转换一下 *******/
$header = explode("\n",$header);
foreach ($header as $k=>$str){
$first_str = '';
if(substr_count($str,':') > 1){
$str = explode(':',$str);
$first_str = $str[0];
if($first_str){
unset($str[0]);
}
$str = implode('_(_(_(_0_)_)_)_',$str);
if($first_str) $str = $first_str.':'.$str;
}
$header[$k] = empty($first_str) ? $str : ltrim($str);
}
$header = implode("\n",$header);
/******end*******/
preg_match_all(
"/^([^\r\n:]+)\s*[:]\s*([^\r\n:]+(?:[\r]?[\n][ \t][^\r\n]+)*)/m",
$header,
$matches,
PREG_SET_ORDER
);
$headers = [];
foreach($matches as $match){
$match[2] = str_replace(['_(_(_(_0_)_)_)_'],[':'],$match[2]);
if(strpos($match[2],'=?')!==false){
$match2=iconv_mime_decode($match[2],ICONV_MIME_DECODE_CONTINUE_ON_ERROR,'utf-8');
$match[2] = $match2;
}
if(isset($headers[$match[1]]) && is_array($headers[$match[1]])){
$headers[$match[1]][]=$match[2];
}elseif(isset($headers[$match[1]])){
$headers[$match[1]]=array($headers[$match[1]],$match[2]);
}else{
$headers[$match[1]]=$match[2];
}
}
return $headers;
}
/**
* 获取邮件内容,包括附件
* @param mixed $data 1,1:10,[1,2,3]
* @param string $saveFilePath 保存附件的目录
* @param bool $is_uid 是否是UID查询
* @throws \Exception
* @author:dc
* @time 2022/11/23 17:01
*/
public function fetchBody($data,$saveFilePath=__DIR__,$is_uid = false){
// 取得body
$result = $this->fetch($data,'body',$is_uid);
foreach ($result as &$item){
if (!empty($item['RFC822.TEXT'])){
// 解析
$item['RFC822.TEXT'] = (new Body($item['RFC822.TEXT'],$saveFilePath))->getItem();
}
}
return $result;
}
/**
* @param $data
* @param false $is_uid
* @return array
* @throws \Exception
* @author:dc
* @time 2022/11/23 10:46
*/
public function fetch($data,$header2Body='header',$is_uid = false):array{
// string 必须是 0:99 开始:结束
if(is_numeric($data)){
$data = intval($data);
}
elseif(is_string($data)){
if(!preg_match("/^\d+:\d+$/",$data)){
$data = '';
}
}elseif (is_array($data)){
foreach ($data as $k=>$v){
if(!is_numeric($v)){
unset($data[$k]);
}
}
$data = array_unique(array_values($data));
$data = implode(',',$data);
}
if(empty($data)){
throw new \Exception('fetch data error');
}
// (UID RFC822.SIZE RFC822.HEADER FLAGS INTERNALDATE BODYSTRUCTURE BODY.PEEK[HEADER.FIELDS (DATE FROM TO SUBJECT CONTENT-TYPE CC REPLY-TO LIST-POST DISPOSITION-NOTIFICATION-TO X-PRIORITY CONTENT-TRANSFER-ENCODING BCC IN-REPLY-TO MAIL-FOLLOWUP-TO MAIL-REPLY-TO MESSAGE-ID REFERENCES RESENT-BCC RETURN-PATH SENDER X-DRAFT-INFO)])
// 指定字段 BODY.PEEK[HEADER.FIELDS (DATE FROM TO ...)]
// 所有header字段 RFC822.HEADER
// RFC822.TEXT 内容包括附件
// body字段必须放最后
if($header2Body=='header'){
// BODY.peek必须放最后
$filed = 'UID FLAGS INTERNALDATE RFC822.SIZE BODYSTRUCTURE BODY.PEEK[HEADER.FIELDS (DATE FROM TO SUBJECT CONTENT-TYPE CC REPLY-TO LIST-POST DISPOSITION-NOTIFICATION-TO X-PRIORITY CONTENT-TRANSFER-ENCODING BCC IN-REPLY-TO MAIL-FOLLOWUP-TO MAIL-REPLY-TO MESSAGE-ID REFERENCES RESENT-BCC RETURN-PATH SENDER X-DRAFT-INFO)]';
}elseif($header2Body=='body'){
$filed = 'RFC822.TEXT';
}else{
$filed = 'UID FLAGS INTERNALDATE';
}
// 读取数据
$result = $this->request(($is_uid?'UID ':'')."FETCH {$data} ($filed)");
if($result[0] != 'ok'){
throw new \Exception('fetch error:'.end($result[1]));
}
// 开始解析数据
$list = [];
foreach ($result[1] as $item){
$item = trim($item);
// 匹配出id和数据
if(preg_match("/\* (\d+) FETCH \(([\w\s\d\r\n\W]{1,})\)$/i",$item,$line)){
$list[$line[1]] = $this->parseFetch($line[2]);
}
}
// 返回结果
return $list;
}
/**
* 解析头部信息,只能解析固定字段的属性
* @param string $line
* @return array
* @author:dc
* @time 2022/11/22 18:06
*/
public function parseFetch($line):array{
$result = [];
$line = ltrim($line);
$header = explode(' ',$line);
do{
switch ($header[0]){
case 'UID':{
$result['UID'] = $header[1];
array_splice($header,0,2);
break;
}
case 'FLAGS':{
// 标记,标签
$result['FLAGS'] = $this->pregFiled(
$header,
"/^\(([\\a-z\s]{0,})\)/Ui"
);
$result['FLAGS'] = $result['FLAGS'] ? explode(' ',$result['FLAGS']) : [];
break;
}
case 'INTERNALDATE':{
// 内部时间
$result['INTERNALDATE'] = $this->pregFiled(
$header,
"/^\"([\\a-z\d\s]{0,})\"/Ui"
);
break;
}
case 'RFC822.SIZE':{
$result['RFC822.SIZE'] = $header[1];
array_splice($header,0,2);
break;
}
case 'BODYSTRUCTURE':{
array_shift($header);
$result['BODYSTRUCTURE'] = '';
$leftNum = $RightNum = 0;
foreach ($header as $key=>$str){
// 还有括号不对等的情况,无语了
if($str == 'BODY[HEADER.FIELDS'){
break;
}
// 找出现的次数
$leftNum += substr_count($str,'(');
$RightNum += substr_count($str,')');
// 拼接起来
$result['BODYSTRUCTURE'] .= ' '.$str;
unset($header[$key]);
// 说明找到结束了
if($leftNum===$RightNum){
break;
}
}
$header = array_values($header);
break;
}
// RFC822.TEXT不能和 BODY[HEADER.FIELDS 同时存在,否则解析失败
case 'RFC822.TEXT':{
array_shift($header);
$result['RFC822.TEXT'] = implode(' ',$header);
$header = [];
break;
}
case 'RFC822.HEADER':{
array_shift($header);
$result['RFC822.HEADER'] = implode(' ',$header);
$header = [];
break;
}
case 'BODY[HEADER.FIELDS':{
// header
$header = implode(' ',$header);
preg_match("/^BODY\[HEADER.FIELDS.*\]/Ui",$header,$m);
// 结果,提出掉字段字符
$result['HEADER.FIELDS'] = ltrim(mb_substr($header,mb_strlen($m[0]),mb_strlen($header)));
$header = [];//表示结束了
break;
}
default:{
array_shift($header);
break;
}
}
}while($header);
return $result;
}
/**
* 匹配字段中的值
* @param $header
* @param $preg
* @return mixed|string
* @author:dc
* @time 2022/11/23 14:38
*/
private function pregFiled(&$header,$preg){
array_shift($header);
// 组成字符串
$header = implode(' ',$header);
// 找flags,非贪婪模式
if(preg_match($preg,$header,$m)){
$header = mb_substr($header,mb_strlen($m[0]),mb_strlen($header));
}
// 打散成数组
$header = explode(' ',$header);
return $m[1]??'';
}
/**
* imap服务器设置的id
* @param array|string $id
* @author:dc
* @time 2022/11/22 11:53
*/
public function setImapId($id){
if(is_array($id)){
$this->imapId = array_merge($this->imapId,$id);
}else{
$this->imapId['name'] = $id;
}
}
/**
* 打开socket链接
* @param int $timeout
* @throws \Exception
* @author:dc
* @time 2022/11/22 14:13
*/
private function socketOpen(int $timeout = 30){
if(!is_resource($this->socket)){
$this->timeout = $timeout ? : 30;
// 链接服务器
$this->socket = stream_socket_client($this->host, $errno, $error, $this->timeout);
if($error){
throw new \Exception("socket error: {$error}");
}
if (!$this->socket) {
throw new \Exception("{$this->host} connection fail.");
}
stream_set_timeout($this->socket, $this->timeout);
}else{
// 是否超时,超时关闭
$meta = stream_get_meta_data($this->socket);
if (isset($meta['timed_out']) && $meta['timed_out'] !== false) {
$this->socketClose();
// 重新链接
$this->socketOpen();
}
}
}
/**
* 最后一次执行时候的tag
* @return string
* @author:dc
* @time 2022/11/22 13:54
*/
protected function getLastTag(){
return sprintf('%s%d', $this->tagName, $this->tagNum);
}
/**
* 获取下一次执行的tag
* @return string
* @author:dc
* @time 2022/11/22 13:52
*/
protected function getNextTag(){
$this->tagNum += 1;
return sprintf('%s%d', $this->tagName, $this->tagNum);
}
/**
* 向服务器发送一个noop消息,表示什么也不做,
* 只是用来保持通信,避免长久没有操作,丢失掉连接
* @throws \Exception
* @author:dc
* @time 2022/11/25 11:15
*/
public function noop():bool {
$status = $this->request('NOOP');
return $status[0] == 'ok';
}
/**
* debug模式
* @param bool $debug
* @param string $logPath
* @author:dc
* @time 2022/12/6 11:10
*/
public function debug($debug=true,$logPath=''){
$this->debug = $debug;
$this->debugWritePath = $logPath ? $logPath : storage_path('logs');
}
/**
* 记录日志
* @param string $message
* @author:dc
* @time 2022/12/6 11:13
*/
private function log(string $message){
if($this->debug){
if(!is_dir($this->debugWritePath)){
@mkdir($this->debugWritePath,0775,true);
}
@file_put_contents($this->debugWritePath.'/imap.log',date('Y-m-d H:i:s ').$message.PHP_EOL,FILE_APPEND);
}
}
/**
* 获取数据集
* @param $cmd
* @return array
* @throws \Exception
* @author:dc
* @time 2022/11/22 11:41
*/
public function request($cmd){
// 链接
$this->socketOpen();
$tag = $this->getNextTag();
// 命令行必须要结束换行
$cmd = trim($tag.' '.$cmd);
// 记录日志
$this->log($cmd);
// 写入数据
$r = fwrite($this->socket, $cmd."\r\n");
if (!$r) {
$this->socketClose();
throw new \Exception("request error write");
}
// 读取数据
$result = []; // 返回数据
$status = 'no'; // 状态
$i = 1;
while ($i) {
$append = false;// 是否追加到上一个元素值里面
// 这里不指定长度,读取一行
$line = @fgets($this->socket);
if ($line === false || !mb_strlen($line)) {
$end = true;
}else{
// 是否有其他的固定串
preg_match("/\{(\d+)\}\r\n$/",$line,$number);
if($number[1]??0){
// 获取到固定字符串
$appendLine = fread($this->socket, intval($number[1]));
// 替换 {123}
$line = str_replace($number[0],$appendLine,$line);
}
// 记录日志
$this->log($line);
// 是否结束了,到了最后一行
if(strpos($line,$tag.' ') === 0){
$end = true;
$status = strtolower(explode(' ',$line)[1]??'');
// 脚本异常
if($status == 'bad'){
throw new \Exception('request bad:'.$line);
}
}else{
if(strpos($line,'* ') !==0 ){
$append = true;
}
}
// 结果数组
if($append){
$result[$i-1] .= $line;
}else{
$result[$i] = $line;
$i++;
}
}
// 结束了
if(!empty($end)){
$i = false;
}
}
// print_r($result);
return [$status,$result];
}
/**
* 是否读取结束
* @return bool
* @author:dc
* @time 2022/11/22 14:14
*/
protected function socketEof()
{
if (!is_resource($this->socket)) {
return true;
}
// If a connection opened by fsockopen() wasn't closed
// by the server, feof() will hang.
$start = microtime(true);
if (feof($this->socket) ||
($this->timeout && (microtime(true) - $start > $this->timeout))
) {
$this->socketClose();
return true;
}
return false;
}
/**
* 关闭socket链接
* @author:dc
* @time 2022/11/22 10:45
*/
protected function socketClose(){
if(is_resource($this->socket)){
fclose($this->socket);
}
$this->socket = false;
}
public function __construct()
{
}
public function __destruct()
{
if($this->auto_colse){
// echo '关闭';
// TODO: Implement __destruct() method.
$this->socketClose();
}
}
}
... ...
<?php
namespace Lib\Mail;
/**
* 操作邮件
* @author:dc
* @time 2023/2/5 10:10
* Class MailFun
* @package Helper\Mail
*/
class Mail {
/**
* imap服务器连接实例
* @var Imap[]
*/
public static array $client = [];
/**
* 登录imap服务器
* @param string $email
* @param string $password
* @param string $imap
* @author:dc
* @time 2023/2/5 10:46
*/
public static function login(string $email,string $password,string $imap) {
if(!empty(static::$client[$email]) && static::$client[$email] instanceof Imap){
if(static::$client[$email]->noop()){
return true;
}
}
static::$client[$email] = new Imap();
// $imap->debug();
// 是否初始成功
static::$client[$email]->login("ssl://{$imap}:993",$email,$password);
return true;
}
/**
* 同步文件夹
* @param $email
* @param MySQL|null $db
* @return mixed
* @author:dc
* @time 2023/2/5 10:58
*/
public static function syncFolder($email,$db=null){
// 读取所有文件夹,未解密
$folders = static::$client[$email]->getFolder();
DB::beginTransaction();
foreach ($folders as $folder){
// 处理子父文件夹
$folder['id'] = explode('/',$folder['folder']);
$folder['name'] = explode('/',$folder['parseFolder']);
$pid = 0;
foreach ($folder['id'] as $k=>$item){
// 插入到数据库
$pid = Folder::_insert(
static::$client[$email]->getId(),
$folder['name'][$k],
$item,
$pid
);
}
}
DB::commit();
}
/**
* 同步邮件
* @param $email
* @param $email_id
* @param $folder_id
* @param string $folder
* @return bool
* @author:dc
* @time 2023/2/6 15:04
*/
public static function syncMail($email,$email_id,$folder_id,$folder='INBOX'):bool {
// 选择文件夹
try {
$status = static::$client[$email]->selectFolder($folder);
}catch (\Throwable $e){
Log::error($email.' 选择文件夹错误:'.$e->getMessage());
return false;
}
// 是否有邮件
if (!isset($status['EXISTS']) || !$status['EXISTS']){
return true;
}
// 更新数量
Folder::_updateNum($folder_id,$status['EXISTS'], $status['UNSEEN']??null);
// 最后拉取的时间,如果是第一次
$lastMsgno = EList::_lastMsgno($email_id, $folder_id);
$nu = 20;
if(!$lastMsgno){
$msgno = range(1,$nu);
}else{
$msgno = range($lastMsgno,$lastMsgno+$nu);
if($lastMsgno > $status['EXISTS']){
$msgno = range($status['EXISTS'] > $nu ? $status['EXISTS'] - $nu : 1,$status['EXISTS']);
}
// 一样就不拉新的
if($lastMsgno == $status['EXISTS']){
return true;
}
}
SYNCEMAILLIST:
// 是否有id
$dataids = EList::_getIdsByMsgno($email_id,$folder_id,$msgno);
// 循环
$results = static::$client[$email]->fetchHeader($msgno);
if($results){
DB::beginTransaction();
// 批量插入
foreach ($results as $key=>$result){
if($key == $status['EXISTS']){
$end = true;
}
$header = &$result['HEADER.FIELDS'];
foreach ($result['FLAGS'] as $k=>$FLAG){
$result['FLAGS'][$k] = strtolower(str_replace('\\','',$FLAG));
}
try {
$file_header = &$result['BODYSTRUCTURE'];
// 没有收件人
if(!empty($header['To'])){
$header['To'] = MailFun::toOrFrom($header['To']);
}else{
$header['To'] = [];
}
$header['From'] = MailFun::toOrFrom($header['From']);
$data = [
'id' => $dataids[$key]??0,
'msgno' => $key,
'uid' => $result['UID'],
'subject' => $header['Subject'],
'cc' => $header['Cc']??'',
'bcc' => $header['Bcc']??'',
'from' => $header['From'][0]['email']??'',
'from_name' => $header['From'][0]['name']??'',
'to' => $header['To']?implode(',',array_column($header['To'],'email')):'',
'to_name' => json_encode($header['To']),
'date' => isset($header['Date'])&&$header['Date'] ? strtotime(is_array($header['Date']) ? $header['Date'][0] : $header['Date']) : strtotime($result['INTERNALDATE']),
'message_id' => $header['Message-ID']??'',
'udate' => strtotime($result['INTERNALDATE']),
// 'size' => $result['RFC822.SIZE'],
'recent' => in_array('recent',$result['FLAGS']),
'seen' => in_array('seen',$result['FLAGS']),
'draft' => in_array('draft',$result['FLAGS']),
'flagged' => in_array('flagged',$result['FLAGS']),
'answered' => in_array('answered',$result['FLAGS']),
'folder_id' => $folder_id,
'email_id' => $email_id,
'uuid' => $email_id.$folder_id.$result['UID'],
'is_file' => MailFun::isFile($file_header[$key]['BODYSTRUCTURE']??[]) //是否附件
];
}catch (\Throwable $e){
Log::error('邮件解析失败:'.$e->getMessage().print_r($result,true));
unset($results[$key]);
continue;
}
$results[$key] = $data;
}
EList::_insertAll(array_values($results));
// 提交
DB::commit();
}
// 再次调用
Mail::syncMail($email,$email_id,$folder_id,$folder);
return true;
}
/**
* 同步 邮件 内容 body
* @param $id
* @param $msgno
* @param $email_id
* @param $folder_name
* @param $email
* @return bool
* @throws \Exception
* @author:dc
* @time 2023/2/9 10:29
*/
public static function syncBody($id,$msgno, $email_id,$folder_name,$email):bool {
// 选择文件夹
static::$client[$email]->selectFolder($folder_name);
$body = static::$client[$email]->fetchBody([$msgno],storage_path('email/'.$email_id));
if(!empty($body[$msgno]['RFC822.TEXT'])){
\App\Models\Body::_insert($id,$body[$msgno]['RFC822.TEXT']);
}
return true;
}
}
... ...
<?php
namespace Helper\Mail;
use Illuminate\Support\Facades\Storage;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
/**
* 函数
* @time 2022/8/1 16:02
* Class MailFun
* @package App\Mail\lib
*/
class MailFun {
/**
* json encode
* @param $data
* @param int $option
* @return false|string
* @time 2022/8/2 15:57
*/
public static function json_en($data,$option=\JSON_UNESCAPED_UNICODE){
return \json_encode($data,$option);
}
/**
* 解码
* @param $string
* @param string $charset
* @return string
* @time 2022/8/15 9:31
*/
public static function decodeMimeStr($string, $charset = 'utf-8') {
$newString = '';
$elements = imap_mime_header_decode($string);
// print_r($elements);
for($i = 0; $i < count($elements); $i++) {
if($elements[$i]->charset == 'default') {
$elements[$i]->charset = 'iso-8859-1';
}
$newString .= self::convertStringEncoding($elements[$i]->text, $elements[$i]->charset, $charset);
}
return $newString;
}
public static function convertStringEncoding($string, $fromEncoding, $toEncoding) {
$convertedString = null;
if($string && $fromEncoding != $toEncoding) {
$convertedString = @iconv($fromEncoding, $toEncoding . '//IGNORE', $string);
if(!$convertedString && extension_loaded('mbstring')) {
$convertedString = @mb_convert_encoding($string, $toEncoding, $fromEncoding);
}
}
return $convertedString ?: $string;
}
/**
* 验证是否有附件 BODYSTRUCTURE值
* @param array $BODYSTRUCTURE
* @return int
* @author:dc
* @time 2022/11/1 10:57
*/
public static function isFile(array $BODYSTRUCTURE):int {
// foreach ($BODYSTRUCTURE as $item){
// if($item[0] === 'APPLICATION'){
// return 1;
// }
// }
// return 0;
$json = json_encode($BODYSTRUCTURE);
return strpos($json,'"attachment"')!==false;
}
/**
* 邮件收件人/发件人
* @param $str
* @return array
* @author:dc
* @time 2022/11/8 9:36
*/
public static function toOrFrom($str){
$strs = explode(',',$str);
foreach ($strs as $k=>$s){
preg_match('/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/',$s,$email);
if(empty($email[0])){
$s = [
'email' => '',
'name' => $s
];
}else{
$s = str_replace([$email[0],'"','<','>','&gt;','&lt;'],'',$s);
$s = trim($s);
$s = [
'email' => $email[0],
'name' => $s
];
}
if(empty($s['name'])){
$s['name'] = explode('@',$s['email'])[0]??'';
}
if(!empty($s['email'])){
$strs[$k] = $s;
}else{
unset($strs[$k]);
}
}
return $strs;
}
/**
* @param string $smtp smtp服务器地址
* @param string $username 发件人
* @param string $password 发件人密码
* @param string $nickname 昵称
* @param string|array $to_email 收件人,邮件或['email'=>'','name'=>'']
* @param string $subject 标题,主题
* @param string $body 文本内容
* @param array $files 文件 ['origin_name'=>'','path'=>'']
* @param false $receipt 是否回执
* @param int $priority 是否紧急 1紧急 3正常 5慢
* @return bool
* @throws \PHPMailer\PHPMailer\Exception
* @author:dc
* @time 2022/11/11 14:26
*/
public static function sendEmail(string $smtp,string $username,string $password,string $nickname,$to_email,string $subject,string $body,$files=[],$receipt=false,$priority=3){
// 邮件对象
$mail = new PHPMailer(true);
//Server settings
$mail->SMTPDebug = SMTP::DEBUG_CLIENT;//调试输出 SMTP::DEBUG_SERVER; //Enable verbose debug output
$mail->isSMTP(); //Send using SMTP
$mail->Host = $smtp; //Set the SMTP server to send through
$mail->SMTPAuth = true; //Enable SMTP authentication
$mail->Username = $username; //SMTP username
$mail->Password = $password; //SMTP password
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; //Enable implicit TLS encryption
$mail->Port = 465; //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`
$mail->CharSet = 'utf-8';
$mail->Encoding = PHPMailer::ENCODING_QUOTED_PRINTABLE;
//Recipients,设置发件人
$mail->setFrom($username, $nickname);// 显示邮件来自谁
// //Add a recipient,设置收件人 这里必须是一对一发送
if(is_array($to_email)){
$mail->addAddress($to_email['email'], $to_email['name']);
}else{
$mail->addAddress($to_email, '');
}
// //回复到那个邮件
// $mail->addAddress($reply_to['email'], $reply_to['name']); //Add a recipient
// // 抄送
// $mail->addCC($cc['email'],$cc['name']);//
// // 密送
// $mail->addBCC($bcc['email'],$bcc['name']);
//Attachments 附件
if($files){
foreach ($files as $file){
// 添加到邮箱中
$mail->addAttachment($file['path'], $file['origin_name']); //Add attachments
}
}
// 回执,阅读后收回执的邮箱
if($receipt){
$mail->ConfirmReadingTo = $receipt;
}
// 是否紧急邮件
// Options: null (default), 1 = High, 3 = Normal, 5 = low.
$mail->Priority = $priority;
//Content 主题,标题
$mail->Subject = $subject;
$mail->isHTML(true); //Set email format to HTML
$mail->Body = $body;// html格式的内容
// 发送
if($mail->send()){
return true;
}
throw new \Exception($mail->ErrorInfo,500);
}
}
... ...
# This file maps Internet media types to unique file extension(s).
# Although created for httpd, this file is used by many software systems
# and has been placed in the public domain for unlimited redisribution.
#
# The table below contains both registered and (common) unregistered types.
# A type that has no unique extension can be ignored -- they are listed
# here to guide configurations toward known types and to make it easier to
# identify "new" types. File extensions are also commonly used to indicate
# content languages and encodings, so choose them carefully.
#
# Internet media types should be registered as described in RFC 4288.
# The registry is at <http://www.iana.org/assignments/media-types/>.
#
# MIME type (lowercased) Extensions
# ============================================ ==========
# application/1d-interleaved-parityfec
# application/3gpdash-qoe-report+xml
# application/3gpp-ims+xml
# application/a2l
# application/activemessage
# application/alto-costmap+json
# application/alto-costmapfilter+json
# application/alto-directory+json
# application/alto-endpointcost+json
# application/alto-endpointcostparams+json
# application/alto-endpointprop+json
# application/alto-endpointpropparams+json
# application/alto-error+json
# application/alto-networkmap+json
# application/alto-networkmapfilter+json
# application/aml
application/andrew-inset ez
# application/applefile
application/applixware aw
# application/atf
# application/atfx
application/atom+xml atom
application/atomcat+xml atomcat
# application/atomdeleted+xml
# application/atomicmail
application/atomsvc+xml atomsvc
# application/atxml
# application/auth-policy+xml
# application/bacnet-xdd+zip
# application/batch-smtp
# application/beep+xml
# application/calendar+json
# application/calendar+xml
# application/call-completion
# application/cals-1840
# application/cbor
# application/ccmp+xml
application/ccxml+xml ccxml
# application/cdfx+xml
application/cdmi-capability cdmia
application/cdmi-container cdmic
application/cdmi-domain cdmid
application/cdmi-object cdmio
application/cdmi-queue cdmiq
# application/cdni
# application/cea
# application/cea-2018+xml
# application/cellml+xml
# application/cfw
# application/cms
# application/cnrp+xml
# application/coap-group+json
# application/commonground
# application/conference-info+xml
# application/cpl+xml
# application/csrattrs
# application/csta+xml
# application/cstadata+xml
# application/csvm+json
application/cu-seeme cu
# application/cybercash
# application/dash+xml
# application/dashdelta
application/davmount+xml davmount
# application/dca-rft
# application/dcd
# application/dec-dx
# application/dialog-info+xml
# application/dicom
# application/dii
# application/dit
# application/dns
application/docbook+xml dbk
# application/dskpp+xml
application/dssc+der dssc
application/dssc+xml xdssc
# application/dvcs
application/ecmascript ecma
# application/edi-consent
# application/edi-x12
# application/edifact
# application/efi
# application/emergencycalldata.comment+xml
# application/emergencycalldata.deviceinfo+xml
# application/emergencycalldata.providerinfo+xml
# application/emergencycalldata.serviceinfo+xml
# application/emergencycalldata.subscriberinfo+xml
application/emma+xml emma
# application/emotionml+xml
# application/encaprtp
# application/epp+xml
application/epub+zip epub
# application/eshop
# application/example
application/exi exi
# application/fastinfoset
# application/fastsoap
# application/fdt+xml
# application/fits
application/font-tdpfr pfr
# application/framework-attributes+xml
# application/geo+json
application/gml+xml gml
application/gpx+xml gpx
application/gxf gxf
# application/gzip
# application/h224
# application/held+xml
# application/http
application/hyperstudio stk
# application/ibe-key-request+xml
# application/ibe-pkg-reply+xml
# application/ibe-pp-data
# application/iges
# application/im-iscomposing+xml
# application/index
# application/index.cmd
# application/index.obj
# application/index.response
# application/index.vnd
application/inkml+xml ink inkml
# application/iotp
application/ipfix ipfix
# application/ipp
# application/isup
# application/its+xml
application/java-archive jar
application/java-serialized-object ser
application/java-vm class
# application/javascript
# application/jose
# application/jose+json
# application/jrd+json
application/json json
# application/json-patch+json
# application/json-seq
application/jsonml+json jsonml
# application/jwk+json
# application/jwk-set+json
# application/jwt
# application/kpml-request+xml
# application/kpml-response+xml
# application/ld+json
# application/lgr+xml
# application/link-format
# application/load-control+xml
application/lost+xml lostxml
# application/lostsync+xml
# application/lxf
application/mac-binhex40 hqx
application/mac-compactpro cpt
# application/macwriteii
application/mads+xml mads
application/marc mrc
application/marcxml+xml mrcx
application/mathematica ma nb mb
application/mathml+xml mathml
# application/mathml-content+xml
# application/mathml-presentation+xml
# application/mbms-associated-procedure-description+xml
# application/mbms-deregister+xml
# application/mbms-envelope+xml
# application/mbms-msk+xml
# application/mbms-msk-response+xml
# application/mbms-protection-description+xml
# application/mbms-reception-report+xml
# application/mbms-register+xml
# application/mbms-register-response+xml
# application/mbms-schedule+xml
# application/mbms-user-service-description+xml
application/mbox mbox
# application/media-policy-dataset+xml
# application/media_control+xml
application/mediaservercontrol+xml mscml
# application/merge-patch+json
application/metalink+xml metalink
application/metalink4+xml meta4
application/mets+xml mets
# application/mf4
# application/mikey
application/mods+xml mods
# application/moss-keys
# application/moss-signature
# application/mosskey-data
# application/mosskey-request
application/mp21 m21 mp21
application/mp4 mp4s
# application/mpeg4-generic
# application/mpeg4-iod
# application/mpeg4-iod-xmt
# application/mrb-consumer+xml
# application/mrb-publish+xml
# application/msc-ivr+xml
# application/msc-mixer+xml
application/msword doc dot
application/mxf mxf
# application/nasdata
# application/news-checkgroups
# application/news-groupinfo
# application/news-transmission
# application/nlsml+xml
# application/nss
# application/ocsp-request
# application/ocsp-response
application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy
application/oda oda
# application/odx
application/oebps-package+xml opf
application/ogg ogx
application/omdoc+xml omdoc
application/onenote onetoc onetoc2 onetmp onepkg
application/oxps oxps
# application/p2p-overlay+xml
# application/parityfec
application/patch-ops-error+xml xer
application/pdf pdf
# application/pdx
application/pgp-encrypted pgp
# application/pgp-keys
application/pgp-signature asc sig
application/pics-rules prf
# application/pidf+xml
# application/pidf-diff+xml
application/pkcs10 p10
# application/pkcs12
application/pkcs7-mime p7m p7c
application/pkcs7-signature p7s
application/pkcs8 p8
application/pkix-attr-cert ac
application/pkix-cert cer
application/pkix-crl crl
application/pkix-pkipath pkipath
application/pkixcmp pki
application/pls+xml pls
# application/poc-settings+xml
application/postscript ai eps ps
# application/ppsp-tracker+json
# application/problem+json
# application/problem+xml
# application/provenance+xml
# application/prs.alvestrand.titrax-sheet
application/prs.cww cww
# application/prs.hpub+zip
# application/prs.nprend
# application/prs.plucker
# application/prs.rdf-xml-crypt
# application/prs.xsf+xml
application/pskc+xml pskcxml
# application/qsig
# application/raptorfec
# application/rdap+json
application/rdf+xml rdf
application/reginfo+xml rif
application/relax-ng-compact-syntax rnc
# application/remote-printing
# application/reputon+json
application/resource-lists+xml rl
application/resource-lists-diff+xml rld
# application/rfc+xml
# application/riscos
# application/rlmi+xml
application/rls-services+xml rs
application/rpki-ghostbusters gbr
application/rpki-manifest mft
application/rpki-roa roa
# application/rpki-updown
application/rsd+xml rsd
application/rss+xml rss
application/rtf rtf
# application/rtploopback
# application/rtx
# application/samlassertion+xml
# application/samlmetadata+xml
application/sbml+xml sbml
# application/scaip+xml
# application/scim+json
application/scvp-cv-request scq
application/scvp-cv-response scs
application/scvp-vp-request spq
application/scvp-vp-response spp
application/sdp sdp
# application/sep+xml
# application/sep-exi
# application/session-info
# application/set-payment
application/set-payment-initiation setpay
# application/set-registration
application/set-registration-initiation setreg
# application/sgml
# application/sgml-open-catalog
application/shf+xml shf
# application/sieve
# application/simple-filter+xml
# application/simple-message-summary
# application/simplesymbolcontainer
# application/slate
# application/smil
application/smil+xml smi smil
# application/smpte336m
# application/soap+fastinfoset
# application/soap+xml
application/sparql-query rq
application/sparql-results+xml srx
# application/spirits-event+xml
# application/sql
application/srgs gram
application/srgs+xml grxml
application/sru+xml sru
application/ssdl+xml ssdl
application/ssml+xml ssml
# application/tamp-apex-update
# application/tamp-apex-update-confirm
# application/tamp-community-update
# application/tamp-community-update-confirm
# application/tamp-error
# application/tamp-sequence-adjust
# application/tamp-sequence-adjust-confirm
# application/tamp-status-query
# application/tamp-status-response
# application/tamp-update
# application/tamp-update-confirm
application/tei+xml tei teicorpus
application/thraud+xml tfi
# application/timestamp-query
# application/timestamp-reply
application/timestamped-data tsd
# application/ttml+xml
# application/tve-trigger
# application/ulpfec
# application/urc-grpsheet+xml
# application/urc-ressheet+xml
# application/urc-targetdesc+xml
# application/urc-uisocketdesc+xml
# application/vcard+json
# application/vcard+xml
# application/vemmi
# application/vividence.scriptfile
# application/vnd.3gpp-prose+xml
# application/vnd.3gpp-prose-pc3ch+xml
# application/vnd.3gpp.access-transfer-events+xml
# application/vnd.3gpp.bsf+xml
# application/vnd.3gpp.mid-call+xml
application/vnd.3gpp.pic-bw-large plb
application/vnd.3gpp.pic-bw-small psb
application/vnd.3gpp.pic-bw-var pvb
# application/vnd.3gpp.sms
# application/vnd.3gpp.sms+xml
# application/vnd.3gpp.srvcc-ext+xml
# application/vnd.3gpp.srvcc-info+xml
# application/vnd.3gpp.state-and-event-info+xml
# application/vnd.3gpp.ussd+xml
# application/vnd.3gpp2.bcmcsinfo+xml
# application/vnd.3gpp2.sms
application/vnd.3gpp2.tcap tcap
# application/vnd.3lightssoftware.imagescal
application/vnd.3m.post-it-notes pwn
application/vnd.accpac.simply.aso aso
application/vnd.accpac.simply.imp imp
application/vnd.acucobol acu
application/vnd.acucorp atc acutc
application/vnd.adobe.air-application-installer-package+zip air
# application/vnd.adobe.flash.movie
application/vnd.adobe.formscentral.fcdt fcdt
application/vnd.adobe.fxp fxp fxpl
# application/vnd.adobe.partial-upload
application/vnd.adobe.xdp+xml xdp
application/vnd.adobe.xfdf xfdf
# application/vnd.aether.imp
# application/vnd.ah-barcode
application/vnd.ahead.space ahead
application/vnd.airzip.filesecure.azf azf
application/vnd.airzip.filesecure.azs azs
application/vnd.amazon.ebook azw
# application/vnd.amazon.mobi8-ebook
application/vnd.americandynamics.acc acc
application/vnd.amiga.ami ami
# application/vnd.amundsen.maze+xml
application/vnd.android.package-archive apk
# application/vnd.anki
application/vnd.anser-web-certificate-issue-initiation cii
application/vnd.anser-web-funds-transfer-initiation fti
application/vnd.antix.game-component atx
# application/vnd.apache.thrift.binary
# application/vnd.apache.thrift.compact
# application/vnd.apache.thrift.json
# application/vnd.api+json
application/vnd.apple.installer+xml mpkg
application/vnd.apple.mpegurl m3u8
# application/vnd.arastra.swi
application/vnd.aristanetworks.swi swi
# application/vnd.artsquare
application/vnd.astraea-software.iota iota
application/vnd.audiograph aep
# application/vnd.autopackage
# application/vnd.avistar+xml
# application/vnd.balsamiq.bmml+xml
# application/vnd.balsamiq.bmpr
# application/vnd.bekitzur-stech+json
# application/vnd.biopax.rdf+xml
application/vnd.blueice.multipass mpm
# application/vnd.bluetooth.ep.oob
# application/vnd.bluetooth.le.oob
application/vnd.bmi bmi
application/vnd.businessobjects rep
# application/vnd.cab-jscript
# application/vnd.canon-cpdl
# application/vnd.canon-lips
# application/vnd.cendio.thinlinc.clientconf
# application/vnd.century-systems.tcp_stream
application/vnd.chemdraw+xml cdxml
# application/vnd.chess-pgn
application/vnd.chipnuts.karaoke-mmd mmd
application/vnd.cinderella cdy
# application/vnd.cirpack.isdn-ext
# application/vnd.citationstyles.style+xml
application/vnd.claymore cla
application/vnd.cloanto.rp9 rp9
application/vnd.clonk.c4group c4g c4d c4f c4p c4u
application/vnd.cluetrust.cartomobile-config c11amc
application/vnd.cluetrust.cartomobile-config-pkg c11amz
# application/vnd.coffeescript
# application/vnd.collection+json
# application/vnd.collection.doc+json
# application/vnd.collection.next+json
# application/vnd.comicbook+zip
# application/vnd.commerce-battelle
application/vnd.commonspace csp
application/vnd.contact.cmsg cdbcmsg
# application/vnd.coreos.ignition+json
application/vnd.cosmocaller cmc
application/vnd.crick.clicker clkx
application/vnd.crick.clicker.keyboard clkk
application/vnd.crick.clicker.palette clkp
application/vnd.crick.clicker.template clkt
application/vnd.crick.clicker.wordbank clkw
application/vnd.criticaltools.wbs+xml wbs
application/vnd.ctc-posml pml
# application/vnd.ctct.ws+xml
# application/vnd.cups-pdf
# application/vnd.cups-postscript
application/vnd.cups-ppd ppd
# application/vnd.cups-raster
# application/vnd.cups-raw
# application/vnd.curl
application/vnd.curl.car car
application/vnd.curl.pcurl pcurl
# application/vnd.cyan.dean.root+xml
# application/vnd.cybank
application/vnd.dart dart
application/vnd.data-vision.rdz rdz
# application/vnd.debian.binary-package
application/vnd.dece.data uvf uvvf uvd uvvd
application/vnd.dece.ttml+xml uvt uvvt
application/vnd.dece.unspecified uvx uvvx
application/vnd.dece.zip uvz uvvz
application/vnd.denovo.fcselayout-link fe_launch
# application/vnd.desmume.movie
# application/vnd.dir-bi.plate-dl-nosuffix
# application/vnd.dm.delegation+xml
application/vnd.dna dna
# application/vnd.document+json
application/vnd.dolby.mlp mlp
# application/vnd.dolby.mobile.1
# application/vnd.dolby.mobile.2
# application/vnd.doremir.scorecloud-binary-document
application/vnd.dpgraph dpg
application/vnd.dreamfactory dfac
# application/vnd.drive+json
application/vnd.ds-keypoint kpxx
# application/vnd.dtg.local
# application/vnd.dtg.local.flash
# application/vnd.dtg.local.html
application/vnd.dvb.ait ait
# application/vnd.dvb.dvbj
# application/vnd.dvb.esgcontainer
# application/vnd.dvb.ipdcdftnotifaccess
# application/vnd.dvb.ipdcesgaccess
# application/vnd.dvb.ipdcesgaccess2
# application/vnd.dvb.ipdcesgpdd
# application/vnd.dvb.ipdcroaming
# application/vnd.dvb.iptv.alfec-base
# application/vnd.dvb.iptv.alfec-enhancement
# application/vnd.dvb.notif-aggregate-root+xml
# application/vnd.dvb.notif-container+xml
# application/vnd.dvb.notif-generic+xml
# application/vnd.dvb.notif-ia-msglist+xml
# application/vnd.dvb.notif-ia-registration-request+xml
# application/vnd.dvb.notif-ia-registration-response+xml
# application/vnd.dvb.notif-init+xml
# application/vnd.dvb.pfr
application/vnd.dvb.service svc
# application/vnd.dxr
application/vnd.dynageo geo
# application/vnd.dzr
# application/vnd.easykaraoke.cdgdownload
# application/vnd.ecdis-update
application/vnd.ecowin.chart mag
# application/vnd.ecowin.filerequest
# application/vnd.ecowin.fileupdate
# application/vnd.ecowin.series
# application/vnd.ecowin.seriesrequest
# application/vnd.ecowin.seriesupdate
# application/vnd.emclient.accessrequest+xml
application/vnd.enliven nml
# application/vnd.enphase.envoy
# application/vnd.eprints.data+xml
application/vnd.epson.esf esf
application/vnd.epson.msf msf
application/vnd.epson.quickanime qam
application/vnd.epson.salt slt
application/vnd.epson.ssf ssf
# application/vnd.ericsson.quickcall
application/vnd.eszigno3+xml es3 et3
# application/vnd.etsi.aoc+xml
# application/vnd.etsi.asic-e+zip
# application/vnd.etsi.asic-s+zip
# application/vnd.etsi.cug+xml
# application/vnd.etsi.iptvcommand+xml
# application/vnd.etsi.iptvdiscovery+xml
# application/vnd.etsi.iptvprofile+xml
# application/vnd.etsi.iptvsad-bc+xml
# application/vnd.etsi.iptvsad-cod+xml
# application/vnd.etsi.iptvsad-npvr+xml
# application/vnd.etsi.iptvservice+xml
# application/vnd.etsi.iptvsync+xml
# application/vnd.etsi.iptvueprofile+xml
# application/vnd.etsi.mcid+xml
# application/vnd.etsi.mheg5
# application/vnd.etsi.overload-control-policy-dataset+xml
# application/vnd.etsi.pstn+xml
# application/vnd.etsi.sci+xml
# application/vnd.etsi.simservs+xml
# application/vnd.etsi.timestamp-token
# application/vnd.etsi.tsl+xml
# application/vnd.etsi.tsl.der
# application/vnd.eudora.data
application/vnd.ezpix-album ez2
application/vnd.ezpix-package ez3
# application/vnd.f-secure.mobile
# application/vnd.fastcopy-disk-image
application/vnd.fdf fdf
application/vnd.fdsn.mseed mseed
application/vnd.fdsn.seed seed dataless
# application/vnd.ffsns
# application/vnd.filmit.zfc
# application/vnd.fints
# application/vnd.firemonkeys.cloudcell
application/vnd.flographit gph
application/vnd.fluxtime.clip ftc
# application/vnd.font-fontforge-sfd
application/vnd.framemaker fm frame maker book
application/vnd.frogans.fnc fnc
application/vnd.frogans.ltf ltf
application/vnd.fsc.weblaunch fsc
application/vnd.fujitsu.oasys oas
application/vnd.fujitsu.oasys2 oa2
application/vnd.fujitsu.oasys3 oa3
application/vnd.fujitsu.oasysgp fg5
application/vnd.fujitsu.oasysprs bh2
# application/vnd.fujixerox.art-ex
# application/vnd.fujixerox.art4
application/vnd.fujixerox.ddd ddd
application/vnd.fujixerox.docuworks xdw
application/vnd.fujixerox.docuworks.binder xbd
# application/vnd.fujixerox.docuworks.container
# application/vnd.fujixerox.hbpl
# application/vnd.fut-misnet
application/vnd.fuzzysheet fzs
application/vnd.genomatix.tuxedo txd
# application/vnd.geo+json
# application/vnd.geocube+xml
application/vnd.geogebra.file ggb
application/vnd.geogebra.tool ggt
application/vnd.geometry-explorer gex gre
application/vnd.geonext gxt
application/vnd.geoplan g2w
application/vnd.geospace g3w
# application/vnd.gerber
# application/vnd.globalplatform.card-content-mgt
# application/vnd.globalplatform.card-content-mgt-response
application/vnd.gmx gmx
application/vnd.google-earth.kml+xml kml
application/vnd.google-earth.kmz kmz
# application/vnd.gov.sk.e-form+xml
# application/vnd.gov.sk.e-form+zip
# application/vnd.gov.sk.xmldatacontainer+xml
application/vnd.grafeq gqf gqs
# application/vnd.gridmp
application/vnd.groove-account gac
application/vnd.groove-help ghf
application/vnd.groove-identity-message gim
application/vnd.groove-injector grv
application/vnd.groove-tool-message gtm
application/vnd.groove-tool-template tpl
application/vnd.groove-vcard vcg
# application/vnd.hal+json
application/vnd.hal+xml hal
application/vnd.handheld-entertainment+xml zmm
application/vnd.hbci hbci
# application/vnd.hcl-bireports
# application/vnd.hdt
# application/vnd.heroku+json
application/vnd.hhe.lesson-player les
application/vnd.hp-hpgl hpgl
application/vnd.hp-hpid hpid
application/vnd.hp-hps hps
application/vnd.hp-jlyt jlt
application/vnd.hp-pcl pcl
application/vnd.hp-pclxl pclxl
# application/vnd.httphone
application/vnd.hydrostatix.sof-data sfd-hdstx
# application/vnd.hyperdrive+json
# application/vnd.hzn-3d-crossword
# application/vnd.ibm.afplinedata
# application/vnd.ibm.electronic-media
application/vnd.ibm.minipay mpy
application/vnd.ibm.modcap afp listafp list3820
application/vnd.ibm.rights-management irm
application/vnd.ibm.secure-container sc
application/vnd.iccprofile icc icm
# application/vnd.ieee.1905
application/vnd.igloader igl
application/vnd.immervision-ivp ivp
application/vnd.immervision-ivu ivu
# application/vnd.ims.imsccv1p1
# application/vnd.ims.imsccv1p2
# application/vnd.ims.imsccv1p3
# application/vnd.ims.lis.v2.result+json
# application/vnd.ims.lti.v2.toolconsumerprofile+json
# application/vnd.ims.lti.v2.toolproxy+json
# application/vnd.ims.lti.v2.toolproxy.id+json
# application/vnd.ims.lti.v2.toolsettings+json
# application/vnd.ims.lti.v2.toolsettings.simple+json
# application/vnd.informedcontrol.rms+xml
# application/vnd.informix-visionary
# application/vnd.infotech.project
# application/vnd.infotech.project+xml
# application/vnd.innopath.wamp.notification
application/vnd.insors.igm igm
application/vnd.intercon.formnet xpw xpx
application/vnd.intergeo i2g
# application/vnd.intertrust.digibox
# application/vnd.intertrust.nncp
application/vnd.intu.qbo qbo
application/vnd.intu.qfx qfx
# application/vnd.iptc.g2.catalogitem+xml
# application/vnd.iptc.g2.conceptitem+xml
# application/vnd.iptc.g2.knowledgeitem+xml
# application/vnd.iptc.g2.newsitem+xml
# application/vnd.iptc.g2.newsmessage+xml
# application/vnd.iptc.g2.packageitem+xml
# application/vnd.iptc.g2.planningitem+xml
application/vnd.ipunplugged.rcprofile rcprofile
application/vnd.irepository.package+xml irp
application/vnd.is-xpr xpr
application/vnd.isac.fcs fcs
application/vnd.jam jam
# application/vnd.japannet-directory-service
# application/vnd.japannet-jpnstore-wakeup
# application/vnd.japannet-payment-wakeup
# application/vnd.japannet-registration
# application/vnd.japannet-registration-wakeup
# application/vnd.japannet-setstore-wakeup
# application/vnd.japannet-verification
# application/vnd.japannet-verification-wakeup
application/vnd.jcp.javame.midlet-rms rms
application/vnd.jisp jisp
application/vnd.joost.joda-archive joda
# application/vnd.jsk.isdn-ngn
application/vnd.kahootz ktz ktr
application/vnd.kde.karbon karbon
application/vnd.kde.kchart chrt
application/vnd.kde.kformula kfo
application/vnd.kde.kivio flw
application/vnd.kde.kontour kon
application/vnd.kde.kpresenter kpr kpt
application/vnd.kde.kspread ksp
application/vnd.kde.kword kwd kwt
application/vnd.kenameaapp htke
application/vnd.kidspiration kia
application/vnd.kinar kne knp
application/vnd.koan skp skd skt skm
application/vnd.kodak-descriptor sse
application/vnd.las.las+xml lasxml
# application/vnd.liberty-request+xml
application/vnd.llamagraphics.life-balance.desktop lbd
application/vnd.llamagraphics.life-balance.exchange+xml lbe
application/vnd.lotus-1-2-3 123
application/vnd.lotus-approach apr
application/vnd.lotus-freelance pre
application/vnd.lotus-notes nsf
application/vnd.lotus-organizer org
application/vnd.lotus-screencam scm
application/vnd.lotus-wordpro lwp
application/vnd.macports.portpkg portpkg
# application/vnd.mapbox-vector-tile
# application/vnd.marlin.drm.actiontoken+xml
# application/vnd.marlin.drm.conftoken+xml
# application/vnd.marlin.drm.license+xml
# application/vnd.marlin.drm.mdcf
# application/vnd.mason+json
# application/vnd.maxmind.maxmind-db
application/vnd.mcd mcd
application/vnd.medcalcdata mc1
application/vnd.mediastation.cdkey cdkey
# application/vnd.meridian-slingshot
application/vnd.mfer mwf
application/vnd.mfmp mfm
# application/vnd.micro+json
application/vnd.micrografx.flo flo
application/vnd.micrografx.igx igx
# application/vnd.microsoft.portable-executable
# application/vnd.miele+json
application/vnd.mif mif
# application/vnd.minisoft-hp3000-save
# application/vnd.mitsubishi.misty-guard.trustweb
application/vnd.mobius.daf daf
application/vnd.mobius.dis dis
application/vnd.mobius.mbk mbk
application/vnd.mobius.mqy mqy
application/vnd.mobius.msl msl
application/vnd.mobius.plc plc
application/vnd.mobius.txf txf
application/vnd.mophun.application mpn
application/vnd.mophun.certificate mpc
# application/vnd.motorola.flexsuite
# application/vnd.motorola.flexsuite.adsi
# application/vnd.motorola.flexsuite.fis
# application/vnd.motorola.flexsuite.gotap
# application/vnd.motorola.flexsuite.kmr
# application/vnd.motorola.flexsuite.ttc
# application/vnd.motorola.flexsuite.wem
# application/vnd.motorola.iprm
application/vnd.mozilla.xul+xml xul
# application/vnd.ms-3mfdocument
application/vnd.ms-artgalry cil
# application/vnd.ms-asf
application/vnd.ms-cab-compressed cab
# application/vnd.ms-color.iccprofile
application/vnd.ms-excel xls xlm xla xlc xlt xlw
application/vnd.ms-excel.addin.macroenabled.12 xlam
application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb
application/vnd.ms-excel.sheet.macroenabled.12 xlsm
application/vnd.ms-excel.template.macroenabled.12 xltm
application/vnd.ms-fontobject eot
application/vnd.ms-htmlhelp chm
application/vnd.ms-ims ims
application/vnd.ms-lrm lrm
# application/vnd.ms-office.activex+xml
application/vnd.ms-officetheme thmx
# application/vnd.ms-opentype
# application/vnd.ms-package.obfuscated-opentype
application/vnd.ms-pki.seccat cat
application/vnd.ms-pki.stl stl
# application/vnd.ms-playready.initiator+xml
application/vnd.ms-powerpoint ppt pps pot
application/vnd.ms-powerpoint.addin.macroenabled.12 ppam
application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm
application/vnd.ms-powerpoint.slide.macroenabled.12 sldm
application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm
application/vnd.ms-powerpoint.template.macroenabled.12 potm
# application/vnd.ms-printdevicecapabilities+xml
# application/vnd.ms-printing.printticket+xml
# application/vnd.ms-printschematicket+xml
application/vnd.ms-project mpp mpt
# application/vnd.ms-tnef
# application/vnd.ms-windows.devicepairing
# application/vnd.ms-windows.nwprinting.oob
# application/vnd.ms-windows.printerpairing
# application/vnd.ms-windows.wsd.oob
# application/vnd.ms-wmdrm.lic-chlg-req
# application/vnd.ms-wmdrm.lic-resp
# application/vnd.ms-wmdrm.meter-chlg-req
# application/vnd.ms-wmdrm.meter-resp
application/vnd.ms-word.document.macroenabled.12 docm
application/vnd.ms-word.template.macroenabled.12 dotm
application/vnd.ms-works wps wks wcm wdb
application/vnd.ms-wpl wpl
application/vnd.ms-xpsdocument xps
# application/vnd.msa-disk-image
application/vnd.mseq mseq
# application/vnd.msign
# application/vnd.multiad.creator
# application/vnd.multiad.creator.cif
# application/vnd.music-niff
application/vnd.musician mus
application/vnd.muvee.style msty
application/vnd.mynfc taglet
# application/vnd.ncd.control
# application/vnd.ncd.reference
# application/vnd.nervana
# application/vnd.netfpx
application/vnd.neurolanguage.nlu nlu
# application/vnd.nintendo.nitro.rom
# application/vnd.nintendo.snes.rom
application/vnd.nitf ntf nitf
application/vnd.noblenet-directory nnd
application/vnd.noblenet-sealer nns
application/vnd.noblenet-web nnw
# application/vnd.nokia.catalogs
# application/vnd.nokia.conml+wbxml
# application/vnd.nokia.conml+xml
# application/vnd.nokia.iptv.config+xml
# application/vnd.nokia.isds-radio-presets
# application/vnd.nokia.landmark+wbxml
# application/vnd.nokia.landmark+xml
# application/vnd.nokia.landmarkcollection+xml
# application/vnd.nokia.n-gage.ac+xml
application/vnd.nokia.n-gage.data ngdat
application/vnd.nokia.n-gage.symbian.install n-gage
# application/vnd.nokia.ncd
# application/vnd.nokia.pcd+wbxml
# application/vnd.nokia.pcd+xml
application/vnd.nokia.radio-preset rpst
application/vnd.nokia.radio-presets rpss
application/vnd.novadigm.edm edm
application/vnd.novadigm.edx edx
application/vnd.novadigm.ext ext
# application/vnd.ntt-local.content-share
# application/vnd.ntt-local.file-transfer
# application/vnd.ntt-local.ogw_remote-access
# application/vnd.ntt-local.sip-ta_remote
# application/vnd.ntt-local.sip-ta_tcp_stream
application/vnd.oasis.opendocument.chart odc
application/vnd.oasis.opendocument.chart-template otc
application/vnd.oasis.opendocument.database odb
application/vnd.oasis.opendocument.formula odf
application/vnd.oasis.opendocument.formula-template odft
application/vnd.oasis.opendocument.graphics odg
application/vnd.oasis.opendocument.graphics-template otg
application/vnd.oasis.opendocument.image odi
application/vnd.oasis.opendocument.image-template oti
application/vnd.oasis.opendocument.presentation odp
application/vnd.oasis.opendocument.presentation-template otp
application/vnd.oasis.opendocument.spreadsheet ods
application/vnd.oasis.opendocument.spreadsheet-template ots
application/vnd.oasis.opendocument.text odt
application/vnd.oasis.opendocument.text-master odm
application/vnd.oasis.opendocument.text-template ott
application/vnd.oasis.opendocument.text-web oth
# application/vnd.obn
# application/vnd.oftn.l10n+json
# application/vnd.oipf.contentaccessdownload+xml
# application/vnd.oipf.contentaccessstreaming+xml
# application/vnd.oipf.cspg-hexbinary
# application/vnd.oipf.dae.svg+xml
# application/vnd.oipf.dae.xhtml+xml
# application/vnd.oipf.mippvcontrolmessage+xml
# application/vnd.oipf.pae.gem
# application/vnd.oipf.spdiscovery+xml
# application/vnd.oipf.spdlist+xml
# application/vnd.oipf.ueprofile+xml
# application/vnd.oipf.userprofile+xml
application/vnd.olpc-sugar xo
# application/vnd.oma-scws-config
# application/vnd.oma-scws-http-request
# application/vnd.oma-scws-http-response
# application/vnd.oma.bcast.associated-procedure-parameter+xml
# application/vnd.oma.bcast.drm-trigger+xml
# application/vnd.oma.bcast.imd+xml
# application/vnd.oma.bcast.ltkm
# application/vnd.oma.bcast.notification+xml
# application/vnd.oma.bcast.provisioningtrigger
# application/vnd.oma.bcast.sgboot
# application/vnd.oma.bcast.sgdd+xml
# application/vnd.oma.bcast.sgdu
# application/vnd.oma.bcast.simple-symbol-container
# application/vnd.oma.bcast.smartcard-trigger+xml
# application/vnd.oma.bcast.sprov+xml
# application/vnd.oma.bcast.stkm
# application/vnd.oma.cab-address-book+xml
# application/vnd.oma.cab-feature-handler+xml
# application/vnd.oma.cab-pcc+xml
# application/vnd.oma.cab-subs-invite+xml
# application/vnd.oma.cab-user-prefs+xml
# application/vnd.oma.dcd
# application/vnd.oma.dcdc
application/vnd.oma.dd2+xml dd2
# application/vnd.oma.drm.risd+xml
# application/vnd.oma.group-usage-list+xml
# application/vnd.oma.lwm2m+json
# application/vnd.oma.lwm2m+tlv
# application/vnd.oma.pal+xml
# application/vnd.oma.poc.detailed-progress-report+xml
# application/vnd.oma.poc.final-report+xml
# application/vnd.oma.poc.groups+xml
# application/vnd.oma.poc.invocation-descriptor+xml
# application/vnd.oma.poc.optimized-progress-report+xml
# application/vnd.oma.push
# application/vnd.oma.scidm.messages+xml
# application/vnd.oma.xcap-directory+xml
# application/vnd.omads-email+xml
# application/vnd.omads-file+xml
# application/vnd.omads-folder+xml
# application/vnd.omaloc-supl-init
# application/vnd.onepager
# application/vnd.openblox.game+xml
# application/vnd.openblox.game-binary
# application/vnd.openeye.oeb
application/vnd.openofficeorg.extension oxt
# application/vnd.openxmlformats-officedocument.custom-properties+xml
# application/vnd.openxmlformats-officedocument.customxmlproperties+xml
# application/vnd.openxmlformats-officedocument.drawing+xml
# application/vnd.openxmlformats-officedocument.drawingml.chart+xml
# application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml
# application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml
# application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml
# application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml
# application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml
# application/vnd.openxmlformats-officedocument.extended-properties+xml
# application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml
# application/vnd.openxmlformats-officedocument.presentationml.comments+xml
# application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml
# application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml
# application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
# application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml
# application/vnd.openxmlformats-officedocument.presentationml.presprops+xml
application/vnd.openxmlformats-officedocument.presentationml.slide sldx
# application/vnd.openxmlformats-officedocument.presentationml.slide+xml
# application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml
# application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml
application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
# application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml
# application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml
# application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml
# application/vnd.openxmlformats-officedocument.presentationml.tags+xml
application/vnd.openxmlformats-officedocument.presentationml.template potx
# application/vnd.openxmlformats-officedocument.presentationml.template.main+xml
# application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
# application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml
application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx
# application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml
# application/vnd.openxmlformats-officedocument.theme+xml
# application/vnd.openxmlformats-officedocument.themeoverride+xml
# application/vnd.openxmlformats-officedocument.vmldrawing
# application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
# application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml
application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
# application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml
# application/vnd.openxmlformats-package.core-properties+xml
# application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml
# application/vnd.openxmlformats-package.relationships+xml
# application/vnd.oracle.resource+json
# application/vnd.orange.indata
# application/vnd.osa.netdeploy
application/vnd.osgeo.mapguide.package mgp
# application/vnd.osgi.bundle
application/vnd.osgi.dp dp
application/vnd.osgi.subsystem esa
# application/vnd.otps.ct-kip+xml
# application/vnd.oxli.countgraph
# application/vnd.pagerduty+json
application/vnd.palm pdb pqa oprc
# application/vnd.panoply
# application/vnd.paos.xml
application/vnd.pawaafile paw
# application/vnd.pcos
application/vnd.pg.format str
application/vnd.pg.osasli ei6
# application/vnd.piaccess.application-licence
application/vnd.picsel efif
application/vnd.pmi.widget wg
# application/vnd.poc.group-advertisement+xml
application/vnd.pocketlearn plf
application/vnd.powerbuilder6 pbd
# application/vnd.powerbuilder6-s
# application/vnd.powerbuilder7
# application/vnd.powerbuilder7-s
# application/vnd.powerbuilder75
# application/vnd.powerbuilder75-s
# application/vnd.preminet
application/vnd.previewsystems.box box
application/vnd.proteus.magazine mgz
application/vnd.publishare-delta-tree qps
application/vnd.pvi.ptid1 ptid
# application/vnd.pwg-multiplexed
# application/vnd.pwg-xhtml-print+xml
# application/vnd.qualcomm.brew-app-res
# application/vnd.quarantainenet
application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb
# application/vnd.quobject-quoxdocument
# application/vnd.radisys.moml+xml
# application/vnd.radisys.msml+xml
# application/vnd.radisys.msml-audit+xml
# application/vnd.radisys.msml-audit-conf+xml
# application/vnd.radisys.msml-audit-conn+xml
# application/vnd.radisys.msml-audit-dialog+xml
# application/vnd.radisys.msml-audit-stream+xml
# application/vnd.radisys.msml-conf+xml
# application/vnd.radisys.msml-dialog+xml
# application/vnd.radisys.msml-dialog-base+xml
# application/vnd.radisys.msml-dialog-fax-detect+xml
# application/vnd.radisys.msml-dialog-fax-sendrecv+xml
# application/vnd.radisys.msml-dialog-group+xml
# application/vnd.radisys.msml-dialog-speech+xml
# application/vnd.radisys.msml-dialog-transform+xml
# application/vnd.rainstor.data
# application/vnd.rapid
# application/vnd.rar
application/vnd.realvnc.bed bed
application/vnd.recordare.musicxml mxl
application/vnd.recordare.musicxml+xml musicxml
# application/vnd.renlearn.rlprint
application/vnd.rig.cryptonote cryptonote
application/vnd.rim.cod cod
application/vnd.rn-realmedia rm
application/vnd.rn-realmedia-vbr rmvb
application/vnd.route66.link66+xml link66
# application/vnd.rs-274x
# application/vnd.ruckus.download
# application/vnd.s3sms
application/vnd.sailingtracker.track st
# application/vnd.sbm.cid
# application/vnd.sbm.mid2
# application/vnd.scribus
# application/vnd.sealed.3df
# application/vnd.sealed.csf
# application/vnd.sealed.doc
# application/vnd.sealed.eml
# application/vnd.sealed.mht
# application/vnd.sealed.net
# application/vnd.sealed.ppt
# application/vnd.sealed.tiff
# application/vnd.sealed.xls
# application/vnd.sealedmedia.softseal.html
# application/vnd.sealedmedia.softseal.pdf
application/vnd.seemail see
application/vnd.sema sema
application/vnd.semd semd
application/vnd.semf semf
application/vnd.shana.informed.formdata ifm
application/vnd.shana.informed.formtemplate itp
application/vnd.shana.informed.interchange iif
application/vnd.shana.informed.package ipk
application/vnd.simtech-mindmapper twd twds
# application/vnd.siren+json
application/vnd.smaf mmf
# application/vnd.smart.notebook
application/vnd.smart.teacher teacher
# application/vnd.software602.filler.form+xml
# application/vnd.software602.filler.form-xml-zip
application/vnd.solent.sdkm+xml sdkm sdkd
application/vnd.spotfire.dxp dxp
application/vnd.spotfire.sfs sfs
# application/vnd.sss-cod
# application/vnd.sss-dtf
# application/vnd.sss-ntf
application/vnd.stardivision.calc sdc
application/vnd.stardivision.draw sda
application/vnd.stardivision.impress sdd
application/vnd.stardivision.math smf
application/vnd.stardivision.writer sdw vor
application/vnd.stardivision.writer-global sgl
application/vnd.stepmania.package smzip
application/vnd.stepmania.stepchart sm
# application/vnd.street-stream
# application/vnd.sun.wadl+xml
application/vnd.sun.xml.calc sxc
application/vnd.sun.xml.calc.template stc
application/vnd.sun.xml.draw sxd
application/vnd.sun.xml.draw.template std
application/vnd.sun.xml.impress sxi
application/vnd.sun.xml.impress.template sti
application/vnd.sun.xml.math sxm
application/vnd.sun.xml.writer sxw
application/vnd.sun.xml.writer.global sxg
application/vnd.sun.xml.writer.template stw
application/vnd.sus-calendar sus susp
application/vnd.svd svd
# application/vnd.swiftview-ics
application/vnd.symbian.install sis sisx
application/vnd.syncml+xml xsm
application/vnd.syncml.dm+wbxml bdm
application/vnd.syncml.dm+xml xdm
# application/vnd.syncml.dm.notification
# application/vnd.syncml.dmddf+wbxml
# application/vnd.syncml.dmddf+xml
# application/vnd.syncml.dmtnds+wbxml
# application/vnd.syncml.dmtnds+xml
# application/vnd.syncml.ds.notification
application/vnd.tao.intent-module-archive tao
application/vnd.tcpdump.pcap pcap cap dmp
# application/vnd.tmd.mediaflex.api+xml
# application/vnd.tml
application/vnd.tmobile-livetv tmo
application/vnd.trid.tpt tpt
application/vnd.triscape.mxs mxs
application/vnd.trueapp tra
# application/vnd.truedoc
# application/vnd.ubisoft.webplayer
application/vnd.ufdl ufd ufdl
application/vnd.uiq.theme utz
application/vnd.umajin umj
application/vnd.unity unityweb
application/vnd.uoml+xml uoml
# application/vnd.uplanet.alert
# application/vnd.uplanet.alert-wbxml
# application/vnd.uplanet.bearer-choice
# application/vnd.uplanet.bearer-choice-wbxml
# application/vnd.uplanet.cacheop
# application/vnd.uplanet.cacheop-wbxml
# application/vnd.uplanet.channel
# application/vnd.uplanet.channel-wbxml
# application/vnd.uplanet.list
# application/vnd.uplanet.list-wbxml
# application/vnd.uplanet.listcmd
# application/vnd.uplanet.listcmd-wbxml
# application/vnd.uplanet.signal
# application/vnd.uri-map
# application/vnd.valve.source.material
application/vnd.vcx vcx
# application/vnd.vd-study
# application/vnd.vectorworks
# application/vnd.vel+json
# application/vnd.verimatrix.vcas
# application/vnd.vidsoft.vidconference
application/vnd.visio vsd vst vss vsw
application/vnd.visionary vis
# application/vnd.vividence.scriptfile
application/vnd.vsf vsf
# application/vnd.wap.sic
# application/vnd.wap.slc
application/vnd.wap.wbxml wbxml
application/vnd.wap.wmlc wmlc
application/vnd.wap.wmlscriptc wmlsc
application/vnd.webturbo wtb
# application/vnd.wfa.p2p
# application/vnd.wfa.wsc
# application/vnd.windows.devicepairing
# application/vnd.wmc
# application/vnd.wmf.bootstrap
# application/vnd.wolfram.mathematica
# application/vnd.wolfram.mathematica.package
application/vnd.wolfram.player nbp
application/vnd.wordperfect wpd
application/vnd.wqd wqd
# application/vnd.wrq-hp3000-labelled
application/vnd.wt.stf stf
# application/vnd.wv.csp+wbxml
# application/vnd.wv.csp+xml
# application/vnd.wv.ssp+xml
# application/vnd.xacml+json
application/vnd.xara xar
application/vnd.xfdl xfdl
# application/vnd.xfdl.webform
# application/vnd.xmi+xml
# application/vnd.xmpie.cpkg
# application/vnd.xmpie.dpkg
# application/vnd.xmpie.plan
# application/vnd.xmpie.ppkg
# application/vnd.xmpie.xlim
application/vnd.yamaha.hv-dic hvd
application/vnd.yamaha.hv-script hvs
application/vnd.yamaha.hv-voice hvp
application/vnd.yamaha.openscoreformat osf
application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg
# application/vnd.yamaha.remote-setup
application/vnd.yamaha.smaf-audio saf
application/vnd.yamaha.smaf-phrase spf
# application/vnd.yamaha.through-ngn
# application/vnd.yamaha.tunnel-udpencap
# application/vnd.yaoweme
application/vnd.yellowriver-custom-menu cmp
application/vnd.zul zir zirz
application/vnd.zzazz.deck+xml zaz
application/voicexml+xml vxml
# application/vq-rtcpxr
# application/watcherinfo+xml
# application/whoispp-query
# application/whoispp-response
application/widget wgt
application/winhlp hlp
# application/wita
# application/wordperfect5.1
application/wsdl+xml wsdl
application/wspolicy+xml wspolicy
application/x-7z-compressed 7z
application/x-abiword abw
application/x-ace-compressed ace
# application/x-amf
application/x-apple-diskimage dmg
application/x-authorware-bin aab x32 u32 vox
application/x-authorware-map aam
application/x-authorware-seg aas
application/x-bcpio bcpio
application/x-bittorrent torrent
application/x-blorb blb blorb
application/x-bzip bz
application/x-bzip2 bz2 boz
application/x-cbr cbr cba cbt cbz cb7
application/x-cdlink vcd
application/x-cfs-compressed cfs
application/x-chat chat
application/x-chess-pgn pgn
# application/x-compress
application/x-conference nsc
application/x-cpio cpio
application/x-csh csh
application/x-debian-package deb udeb
application/x-dgc-compressed dgc
application/x-director dir dcr dxr cst cct cxt w3d fgd swa
application/x-doom wad
application/x-dtbncx+xml ncx
application/x-dtbook+xml dtb
application/x-dtbresource+xml res
application/x-dvi dvi
application/x-envoy evy
application/x-eva eva
application/x-font-bdf bdf
# application/x-font-dos
# application/x-font-framemaker
application/x-font-ghostscript gsf
# application/x-font-libgrx
application/x-font-linux-psf psf
application/x-font-pcf pcf
application/x-font-snf snf
# application/x-font-speedo
# application/x-font-sunos-news
application/x-font-type1 pfa pfb pfm afm
# application/x-font-vfont
application/x-freearc arc
application/x-futuresplash spl
application/x-gca-compressed gca
application/x-glulx ulx
application/x-gnumeric gnumeric
application/x-gramps-xml gramps
application/x-gtar gtar
# application/x-gzip
application/x-hdf hdf
application/x-install-instructions install
application/x-iso9660-image iso
application/x-java-jnlp-file jnlp
application/x-latex latex
application/x-lzh-compressed lzh lha
application/x-mie mie
application/x-mobipocket-ebook prc mobi
application/x-ms-application application
application/x-ms-shortcut lnk
application/x-ms-wmd wmd
application/x-ms-wmz wmz
application/x-ms-xbap xbap
application/x-msaccess mdb
application/x-msbinder obd
application/x-mscardfile crd
application/x-msclip clp
application/x-msdownload exe dll com bat msi
application/x-msmediaview mvb m13 m14
application/x-msmetafile wmf wmz emf emz
application/x-msmoney mny
application/x-mspublisher pub
application/x-msschedule scd
application/x-msterminal trm
application/x-mswrite wri
application/x-netcdf nc cdf
application/x-nzb nzb
application/x-pkcs12 p12 pfx
application/x-pkcs7-certificates p7b spc
application/x-pkcs7-certreqresp p7r
application/x-rar-compressed rar
application/x-research-info-systems ris
application/x-sh sh
application/x-shar shar
application/x-shockwave-flash swf
application/x-silverlight-app xap
application/x-sql sql
application/x-stuffit sit
application/x-stuffitx sitx
application/x-subrip srt
application/x-sv4cpio sv4cpio
application/x-sv4crc sv4crc
application/x-t3vm-image t3
application/x-tads gam
application/x-tar tar
application/x-tcl tcl
application/x-tex tex
application/x-tex-tfm tfm
application/x-texinfo texinfo texi
application/x-tgif obj
application/x-ustar ustar
application/x-wais-source src
# application/x-www-form-urlencoded
application/x-x509-ca-cert der crt
application/x-xfig fig
application/x-xliff+xml xlf
application/x-xpinstall xpi
application/x-xz xz
application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8
# application/x400-bp
# application/xacml+xml
application/xaml+xml xaml
# application/xcap-att+xml
# application/xcap-caps+xml
application/xcap-diff+xml xdf
# application/xcap-el+xml
# application/xcap-error+xml
# application/xcap-ns+xml
# application/xcon-conference-info+xml
# application/xcon-conference-info-diff+xml
application/xenc+xml xenc
application/xhtml+xml xhtml xht
# application/xhtml-voice+xml
application/xml xml xsl
application/xml-dtd dtd
# application/xml-external-parsed-entity
# application/xml-patch+xml
# application/xmpp+xml
application/xop+xml xop
application/xproc+xml xpl
application/xslt+xml xslt
application/xspf+xml xspf
application/xv+xml mxml xhvml xvml xvm
application/yang yang
application/yin+xml yin
application/zip zip
# application/zlib
# audio/1d-interleaved-parityfec
# audio/32kadpcm
# audio/3gpp
# audio/3gpp2
# audio/ac3
audio/adpcm adp
# audio/amr
# audio/amr-wb
# audio/amr-wb+
# audio/aptx
# audio/asc
# audio/atrac-advanced-lossless
# audio/atrac-x
# audio/atrac3
audio/basic au snd
# audio/bv16
# audio/bv32
# audio/clearmode
# audio/cn
# audio/dat12
# audio/dls
# audio/dsr-es201108
# audio/dsr-es202050
# audio/dsr-es202211
# audio/dsr-es202212
# audio/dv
# audio/dvi4
# audio/eac3
# audio/encaprtp
# audio/evrc
# audio/evrc-qcp
# audio/evrc0
# audio/evrc1
# audio/evrcb
# audio/evrcb0
# audio/evrcb1
# audio/evrcnw
# audio/evrcnw0
# audio/evrcnw1
# audio/evrcwb
# audio/evrcwb0
# audio/evrcwb1
# audio/evs
# audio/example
# audio/fwdred
# audio/g711-0
# audio/g719
# audio/g722
# audio/g7221
# audio/g723
# audio/g726-16
# audio/g726-24
# audio/g726-32
# audio/g726-40
# audio/g728
# audio/g729
# audio/g7291
# audio/g729d
# audio/g729e
# audio/gsm
# audio/gsm-efr
# audio/gsm-hr-08
# audio/ilbc
# audio/ip-mr_v2.5
# audio/isac
# audio/l16
# audio/l20
# audio/l24
# audio/l8
# audio/lpc
audio/midi mid midi kar rmi
# audio/mobile-xmf
audio/mp4 m4a mp4a
# audio/mp4a-latm
# audio/mpa
# audio/mpa-robust
audio/mpeg mpga mp2 mp2a mp3 m2a m3a
# audio/mpeg4-generic
# audio/musepack
audio/ogg oga ogg spx opus
# audio/opus
# audio/parityfec
# audio/pcma
# audio/pcma-wb
# audio/pcmu
# audio/pcmu-wb
# audio/prs.sid
# audio/qcelp
# audio/raptorfec
# audio/red
# audio/rtp-enc-aescm128
# audio/rtp-midi
# audio/rtploopback
# audio/rtx
audio/s3m s3m
audio/silk sil
# audio/smv
# audio/smv-qcp
# audio/smv0
# audio/sp-midi
# audio/speex
# audio/t140c
# audio/t38
# audio/telephone-event
# audio/tone
# audio/uemclip
# audio/ulpfec
# audio/vdvi
# audio/vmr-wb
# audio/vnd.3gpp.iufp
# audio/vnd.4sb
# audio/vnd.audiokoz
# audio/vnd.celp
# audio/vnd.cisco.nse
# audio/vnd.cmles.radio-events
# audio/vnd.cns.anp1
# audio/vnd.cns.inf1
audio/vnd.dece.audio uva uvva
audio/vnd.digital-winds eol
# audio/vnd.dlna.adts
# audio/vnd.dolby.heaac.1
# audio/vnd.dolby.heaac.2
# audio/vnd.dolby.mlp
# audio/vnd.dolby.mps
# audio/vnd.dolby.pl2
# audio/vnd.dolby.pl2x
# audio/vnd.dolby.pl2z
# audio/vnd.dolby.pulse.1
audio/vnd.dra dra
audio/vnd.dts dts
audio/vnd.dts.hd dtshd
# audio/vnd.dvb.file
# audio/vnd.everad.plj
# audio/vnd.hns.audio
audio/vnd.lucent.voice lvp
audio/vnd.ms-playready.media.pya pya
# audio/vnd.nokia.mobile-xmf
# audio/vnd.nortel.vbk
audio/vnd.nuera.ecelp4800 ecelp4800
audio/vnd.nuera.ecelp7470 ecelp7470
audio/vnd.nuera.ecelp9600 ecelp9600
# audio/vnd.octel.sbc
# audio/vnd.qcelp
# audio/vnd.rhetorex.32kadpcm
audio/vnd.rip rip
# audio/vnd.sealedmedia.softseal.mpeg
# audio/vnd.vmx.cvsd
# audio/vorbis
# audio/vorbis-config
audio/webm weba
audio/x-aac aac
audio/x-aiff aif aiff aifc
audio/x-caf caf
audio/x-flac flac
audio/x-matroska mka
audio/x-mpegurl m3u
audio/x-ms-wax wax
audio/x-ms-wma wma
audio/x-pn-realaudio ram ra
audio/x-pn-realaudio-plugin rmp
# audio/x-tta
audio/x-wav wav
audio/xm xm
chemical/x-cdx cdx
chemical/x-cif cif
chemical/x-cmdf cmdf
chemical/x-cml cml
chemical/x-csml csml
# chemical/x-pdb
chemical/x-xyz xyz
font/collection ttc
font/otf otf
# font/sfnt
font/ttf ttf
font/woff woff
font/woff2 woff2
image/bmp bmp
image/cgm cgm
# image/dicom-rle
# image/emf
# image/example
# image/fits
image/g3fax g3
image/gif gif
image/ief ief
# image/jls
# image/jp2
image/jpeg jpeg jpg jpe
# image/jpm
# image/jpx
image/ktx ktx
# image/naplps
image/png png
image/prs.btif btif
# image/prs.pti
# image/pwg-raster
image/sgi sgi
image/svg+xml svg svgz
# image/t38
image/tiff tiff tif
# image/tiff-fx
image/vnd.adobe.photoshop psd
# image/vnd.airzip.accelerator.azv
# image/vnd.cns.inf2
image/vnd.dece.graphic uvi uvvi uvg uvvg
image/vnd.djvu djvu djv
image/vnd.dvb.subtitle sub
image/vnd.dwg dwg
image/vnd.dxf dxf
image/vnd.fastbidsheet fbs
image/vnd.fpx fpx
image/vnd.fst fst
image/vnd.fujixerox.edmics-mmr mmr
image/vnd.fujixerox.edmics-rlc rlc
# image/vnd.globalgraphics.pgb
# image/vnd.microsoft.icon
# image/vnd.mix
# image/vnd.mozilla.apng
image/vnd.ms-modi mdi
image/vnd.ms-photo wdp
image/vnd.net-fpx npx
# image/vnd.radiance
# image/vnd.sealed.png
# image/vnd.sealedmedia.softseal.gif
# image/vnd.sealedmedia.softseal.jpg
# image/vnd.svf
# image/vnd.tencent.tap
# image/vnd.valve.source.texture
image/vnd.wap.wbmp wbmp
image/vnd.xiff xif
# image/vnd.zbrush.pcx
image/webp webp
# image/wmf
image/x-3ds 3ds
image/x-cmu-raster ras
image/x-cmx cmx
image/x-freehand fh fhc fh4 fh5 fh7
image/x-icon ico
image/x-mrsid-image sid
image/x-pcx pcx
image/x-pict pic pct
image/x-portable-anymap pnm
image/x-portable-bitmap pbm
image/x-portable-graymap pgm
image/x-portable-pixmap ppm
image/x-rgb rgb
image/x-tga tga
image/x-xbitmap xbm
image/x-xpixmap xpm
image/x-xwindowdump xwd
# message/cpim
# message/delivery-status
# message/disposition-notification
# message/example
# message/external-body
# message/feedback-report
# message/global
# message/global-delivery-status
# message/global-disposition-notification
# message/global-headers
# message/http
# message/imdn+xml
# message/news
# message/partial
message/rfc822 eml mime
# message/s-http
# message/sip
# message/sipfrag
# message/tracking-status
# message/vnd.si.simp
# message/vnd.wfa.wsc
# model/example
# model/gltf+json
model/iges igs iges
model/mesh msh mesh silo
model/vnd.collada+xml dae
model/vnd.dwf dwf
# model/vnd.flatland.3dml
model/vnd.gdl gdl
# model/vnd.gs-gdl
# model/vnd.gs.gdl
model/vnd.gtw gtw
# model/vnd.moml+xml
model/vnd.mts mts
# model/vnd.opengex
# model/vnd.parasolid.transmit.binary
# model/vnd.parasolid.transmit.text
# model/vnd.rosette.annotated-data-model
# model/vnd.valve.source.compiled-map
model/vnd.vtu vtu
model/vrml wrl vrml
model/x3d+binary x3db x3dbz
# model/x3d+fastinfoset
model/x3d+vrml x3dv x3dvz
model/x3d+xml x3d x3dz
# model/x3d-vrml
# multipart/alternative
# multipart/appledouble
# multipart/byteranges
# multipart/digest
# multipart/encrypted
# multipart/example
# multipart/form-data
# multipart/header-set
# multipart/mixed
# multipart/parallel
# multipart/related
# multipart/report
# multipart/signed
# multipart/voice-message
# multipart/x-mixed-replace
# text/1d-interleaved-parityfec
text/cache-manifest appcache
text/calendar ics ifb
text/css css
text/csv csv
# text/csv-schema
# text/directory
# text/dns
# text/ecmascript
# text/encaprtp
# text/enriched
# text/example
# text/fwdred
# text/grammar-ref-list
text/html html htm
text/javascript js mjs
# text/jcr-cnd
# text/markdown
# text/mizar
text/n3 n3
# text/parameters
# text/parityfec
text/plain txt text conf def list log in
# text/provenance-notation
# text/prs.fallenstein.rst
text/prs.lines.tag dsc
# text/prs.prop.logic
# text/raptorfec
# text/red
# text/rfc822-headers
text/richtext rtx
# text/rtf
# text/rtp-enc-aescm128
# text/rtploopback
# text/rtx
text/sgml sgml sgm
# text/t140
text/tab-separated-values tsv
text/troff t tr roff man me ms
text/turtle ttl
# text/ulpfec
text/uri-list uri uris urls
text/vcard vcard
# text/vnd.a
# text/vnd.abc
text/vnd.curl curl
text/vnd.curl.dcurl dcurl
text/vnd.curl.mcurl mcurl
text/vnd.curl.scurl scurl
# text/vnd.debian.copyright
# text/vnd.dmclientscript
text/vnd.dvb.subtitle sub
# text/vnd.esmertec.theme-descriptor
text/vnd.fly fly
text/vnd.fmi.flexstor flx
text/vnd.graphviz gv
text/vnd.in3d.3dml 3dml
text/vnd.in3d.spot spot
# text/vnd.iptc.newsml
# text/vnd.iptc.nitf
# text/vnd.latex-z
# text/vnd.motorola.reflex
# text/vnd.ms-mediapackage
# text/vnd.net2phone.commcenter.command
# text/vnd.radisys.msml-basic-layout
# text/vnd.si.uricatalogue
text/vnd.sun.j2me.app-descriptor jad
# text/vnd.trolltech.linguist
# text/vnd.wap.si
# text/vnd.wap.sl
text/vnd.wap.wml wml
text/vnd.wap.wmlscript wmls
text/x-asm s asm
text/x-c c cc cxx cpp h hh dic
text/x-fortran f for f77 f90
text/x-java-source java
text/x-nfo nfo
text/x-opml opml
text/x-pascal p pas
text/x-setext etx
text/x-sfv sfv
text/x-uuencode uu
text/x-vcalendar vcs
text/x-vcard vcf
# text/xml
# text/xml-external-parsed-entity
# video/1d-interleaved-parityfec
video/3gpp 3gp
# video/3gpp-tt
video/3gpp2 3g2
# video/bmpeg
# video/bt656
# video/celb
# video/dv
# video/encaprtp
# video/example
video/h261 h261
video/h263 h263
# video/h263-1998
# video/h263-2000
video/h264 h264
# video/h264-rcdo
# video/h264-svc
# video/h265
# video/iso.segment
video/jpeg jpgv
# video/jpeg2000
video/jpm jpm jpgm
video/mj2 mj2 mjp2
# video/mp1s
# video/mp2p
# video/mp2t
video/mp4 mp4 mp4v mpg4
# video/mp4v-es
video/mpeg mpeg mpg mpe m1v m2v
# video/mpeg4-generic
# video/mpv
# video/nv
video/ogg ogv
# video/parityfec
# video/pointer
video/quicktime qt mov
# video/raptorfec
# video/raw
# video/rtp-enc-aescm128
# video/rtploopback
# video/rtx
# video/smpte292m
# video/ulpfec
# video/vc1
# video/vnd.cctv
video/vnd.dece.hd uvh uvvh
video/vnd.dece.mobile uvm uvvm
# video/vnd.dece.mp4
video/vnd.dece.pd uvp uvvp
video/vnd.dece.sd uvs uvvs
video/vnd.dece.video uvv uvvv
# video/vnd.directv.mpeg
# video/vnd.directv.mpeg-tts
# video/vnd.dlna.mpeg-tts
video/vnd.dvb.file dvb
video/vnd.fvt fvt
# video/vnd.hns.video
# video/vnd.iptvforum.1dparityfec-1010
# video/vnd.iptvforum.1dparityfec-2005
# video/vnd.iptvforum.2dparityfec-1010
# video/vnd.iptvforum.2dparityfec-2005
# video/vnd.iptvforum.ttsavc
# video/vnd.iptvforum.ttsmpeg2
# video/vnd.motorola.video
# video/vnd.motorola.videop
video/vnd.mpegurl mxu m4u
video/vnd.ms-playready.media.pyv pyv
# video/vnd.nokia.interleaved-multimedia
# video/vnd.nokia.videovoip
# video/vnd.objectvideo
# video/vnd.radgamettools.bink
# video/vnd.radgamettools.smacker
# video/vnd.sealed.mpeg1
# video/vnd.sealed.mpeg4
# video/vnd.sealed.swf
# video/vnd.sealedmedia.softseal.mov
video/vnd.uvvu.mp4 uvu uvvu
video/vnd.vivo viv
# video/vp8
video/webm webm
video/x-f4v f4v
video/x-fli fli
video/x-flv flv
video/x-m4v m4v
video/x-matroska mkv mk3d mks
video/x-mng mng
video/x-ms-asf asf asx
video/x-ms-vob vob
video/x-ms-wm wm
video/x-ms-wmv wmv
video/x-ms-wmx wmx
video/x-ms-wvx wvx
video/x-msvideo avi
video/x-sgi-movie movie
video/x-smv smv
x-conference/x-cooltalk ice
... ...
此 diff 太大无法显示。
... ... @@ -3,7 +3,7 @@
namespace Lib;
/**
* redis 链接池
* redis 链接池 swoole内置了链接池,自能在协程中使用,所以单独写出来
* @author:dc
* @time 2023/2/10 17:04
* Class RedisPool
... ... @@ -25,7 +25,7 @@ class RedisPool {
{
$this->client = new \Redis();
$this->client->connect(REDIS_HOST,REDIS_PORT);
$this->client->connect(REDIS_HOST,REDIS_PORT,1);
// 密码
REDIS_PASSWORD && $this->client->auth(REDIS_PASSWORD);
// 用库4
... ... @@ -136,6 +136,18 @@ class RedisPool {
}
/**
* 删除
* @param $key
* @return int
* @author:dc
* @time 2023/2/14 14:04
*/
public function delete($key):int {
return $this->client->del($key);
}
/**
* @param $val
... ... @@ -163,7 +175,12 @@ class RedisPool {
public function __destruct()
{
// TODO: Implement __destruct() method.
$this->client->close();
try {
if($this->client->ping()){
$this->client->close();
}
}catch (\RedisException $e){}
$this->client = null;
}
... ... @@ -178,6 +195,13 @@ class RedisPool {
if(empty(static::$instance[$cid])){
static::$instance[$cid] = new \Lib\RedisPool();
}
// ping失败了说明连接炸了
try {
static::$instance[$cid]->client->ping();
}catch (\RedisException $e){
static::$instance[$cid] = new \Lib\RedisPool();
}
return static::$instance[$cid];
}
... ...
... ... @@ -17,7 +17,7 @@ class email {
* @author:dc
* @time 2023/2/13 14:50
*/
public static function first($email){
public static function first($email):array {
return [
"select * from `emails` where `email` = ? limit 1",
[
... ... @@ -26,5 +26,15 @@ class email {
];
}
/**
* 统计邮箱的数量
* @return string
* @author:dc
* @time 2023/2/14 16:16
*/
public static function count():string {
return "select count(*) from `emails` limit 1";
}
}
... ...