收件箱读取(初始版本)

This commit is contained in:
wangzhaocui
2022-04-24 14:27:33 +08:00
parent 6937919d48
commit 50dd6ebb44
3 changed files with 631 additions and 0 deletions

4
.env
View File

@@ -6,6 +6,10 @@ send_email_password = Wu999999tmrwe
;审核建议邮箱
editor_email = publisher@tmrjournals.com
;读取的企业邮箱
mail_server = imap.qq.com
[journal]
;官网服务器地址
base_url = http://journalapi.tmrjournals.com/public/index.php

View File

@@ -0,0 +1,202 @@
<?php
namespace app\api\controller;
use email\receiveMails;
use think\Controller;
use think\Db;
use think\Env;
use think\Validate;
class Inbox extends Controller{
protected $inbox_obj = '';
protected $inbox_attachment_obj = '';
protected $journal_obj = '';
public function __construct(\think\Request $request = null) {
parent::__construct($request);
$this->inbox_obj = Db::name('inbox');
$this->inbox_attachment_obj = Db::name('inbox_attachment');
$this->journal_obj = Db::name('journal');
}
/**
* 获取收件箱邮件
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function getInbox(){
$server = new receiveMails();
$journals=[
[ 'journal_id'=>2,
'email'=>'1586428462@qq.com',
'epassword'=>'rthlprelzzfphigh'
]
];
foreach ($journals as $journal){
//1. 连接邮箱 传入参数
$server->connect($journal);
//2. 获取邮件数
$emailNums = $server->getTotalMails();
if($emailNums){
$insertData=[];
foreach ($emailNums as $key=>$value){
//2.1 获取邮件头部信息
$head = $server->getHeaders($value);
//2.2 处理邮件附件
$files = $server->getAttach($value);
// 附件
$head['url'] =[];
//2.3 处理正文中的图片
$imageList=array();
$section = 2;
if($files){
foreach($files as $k => $file)
{
//type=1为附件,0为邮件内容图片
if($file['type'] == 0)
{
$imageList[$k]=$file['pathname'];
}
if($file['type'] == 1)
{
array_push($head['url'],$file['url']);
}
if(($file['type'] == 0 || $file['type'] == 1) && !empty($file['url'])){
$section = 1.2 ;
}
}
}
$webPath = ROOT_PATH.'public' . DS . 'contentImg' . DS . date('Ymd') .DS ;
// 正文内容
$head['content'] = $server->getBody($value,$webPath,$imageList,$section);
array_push($insertData,$head);
}
$this->insertData($insertData,$journal);
}
}
}
// 后台展示 收件箱
public function getInboxList(){
$data = $this->request->post();
// 验证规则
$rule = new Validate([
'pageIndex'=>'require|number',
'pageSize'=>'require|number'
]);
if(!$rule->check($data)){
return json(['code' => 1,'msg'=>$rule->getError()]);
}
$res['data'] = $this->inbox_obj->field('t_inbox.*,t_inbox_attachment.attachmentUrl')
->join('t_inbox_attachment','t_inbox_attachment.emailId = t_inbox.id','LEFT')
->page($data['pageIndex'],$data['pageSize'])
->select();
$res['data']= $this->inbox_obj->field('id,sendEmail,title,content,creatTime,isaAtachment')->page($data['pageIndex'],$data['pageSize'])->select();
foreach ($res['data'] as $key=>$value ){
$res['data'][$key]['attachmentUrl'] = $this->inbox_attachment_obj->where('emailId',$value['id'])->column('attachmentUrl');
}
$res['total'] = $this->inbox_obj->count();
return jsonSuccess($res);
}
/**
* 已经存在邮件去除
* @param $datas
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
private function removeData($datas,$journal){
foreach ($datas as $key => $value){
$res = $this->inbox_obj->where(['journalId'=>$journal['journal_id'],'eid'=>$value['emailId']])->find();
if($res){
unset($datas[$key]);
}
}
return $datas;
}
/**
* 写入数据库
* @param $datas
*/
private function insertData($datas,$journal){
$datas = $this->removeData($datas,$journal);
Db::startTrans();
try{
foreach ($datas as $key=>$value){
$insert = [
'journalId'=>$journal['journal_id'],
'eid'=>$value['emailId'],
'sendEmail'=>$value['from'],
'title'=>$value['subject'],
'content'=>$value['content'],
'sendTime'=>$value['sendTime'],
'creatTime'=>time(),
'isaAtachment'=>empty($value['url'])?0:1,
'isReply'=>$value['isReply']
];
$id = $this->inbox_obj->insertGetId($insert);
if(!empty($value['url']) && is_array($value['url'])){
$urls=[];
foreach ($value['url'] as $k => $url){
$urls[$k]=[
'emailId'=>$id,
'attachmentUrl'=>$url
];
}
$this->inbox_attachment_obj->insertAll($urls);
}
}
//提交事务
Db::commit();
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
}
}
}

View File

@@ -0,0 +1,425 @@
<?php
namespace email;
use think\Env;
class receiveMails{
var $marubox='';
/**
* 连接 邮箱
* @param $data
* @return bool
*/
function connect($data) //Connect To the Mail Box
{
$mailServer = Env::get('email.mail_server');
$mailLink="{{$mailServer}:143}" ; //imagp连接地址不同主机地址不同
$mailUser = $data['email'];
$mailPass = $data['epassword'];
$this->marubox = imap_open($mailLink,$mailUser,$mailPass);
if (!$this->marubox) {
echo "Error: Connecting to mail server";
exit;
}
return true;
}
/**
* 获取邮件数
* @return false|int
*/
function getTotalMails()
{
if (!$this->marubox){
return false;
}
$date = date("j F Y");
$emails = imap_search($this->marubox,'SINCE "'.$date.'"');
return $emails;
}
/**
* 获取邮件头部信息
* @param $mid
* @return array|false
*/
function getHeaders($mid) // Get Header info
{
if (!$this->marubox){
return false;
}
$mail_header = imap_header($this->marubox, $mid);
$sender = $mail_header->from[0];
if (strtolower($sender->mailbox) != 'mailer-daemon' && strtolower($sender->mailbox) != 'postmaster') {
$subject = $this->decode_mime($mail_header->subject);
$mail_details = array(
'emailId'=>$mid,
'from' => strtolower($sender->mailbox) . '@' . $sender->host,
'subject'=>$subject,//imap_mime_header_decode($mail_header->subject)[0]->text,
'sendTime' => $mail_header->udate,
'isReply'=>0
);
$reply = substr($mail_details['subject'],0,2);
if($reply == 'RE' || $reply == 'Re' ){
$mail_details['isReply'] = 1;
}
}
return $mail_details;
}
/**
* 处理邮件附件
* @param $mid
* @return array|false
*/
function getAttach($mid) // Get Atteced File from Mail
{
if (!$this->marubox){
return false;
}
$struckture = imap_fetchstructure($this->marubox, $mid);
$files = array();
if ($struckture->parts) {
foreach ($struckture->parts as $key => $value) {
$enc = $struckture->parts[$key]->encoding;
//取邮件附件
if ($struckture->parts[$key]->ifdparameters) {
//命名附件,转码
$name = $this->decode_mime($struckture->parts[$key]->dparameters[0]->value);
$extend = explode(".", $name);
$file['extension'] = $extend[count($extend) - 1];
$file['pathname'] = $this->setPathName($mid, $key, $file['extension']);
$file['title'] = !empty($name) ? htmlspecialchars($name) : str_replace('.' . $file['extension'], '', $name);
if (@$struckture->parts[$key]->disposition == "attachment") { // 是附件
$path = ROOT_PATH.'public' . DS . 'downAttachment' . DS . date('Ymd') .DS;
$file['type'] = 1;
} else { // 是正文内容
$file['type'] = 0;
$path = ROOT_PATH.'public' . DS . 'contentImg' . DS . date('Ymd') .DS;
}
$message = imap_fetchbody($this->marubox, $mid, $key + 1);
if ($enc == 0){
$message = imap_8bit($message);
}
if ($enc == 1){
$message = imap_8bit($message);
}
if ($enc == 2){
$message = imap_binary($message);
}
if ($enc == 3){//图片
$message = imap_base64($message);
}
if ($enc == 4){
$message = quoted_printable_decode($message);
}
if ($enc == 5){
$message = $message;
}
if (!file_exists($path)){
mkdir($path,0777,true);
}
$fp = fopen($path . $file['pathname'], "w+");
fwrite($fp, $message);
fclose($fp);
$file['url']=$path . $file['pathname'];
$files[] = $file;
}
// 处理内容中包含图片的部分
if($key == 0){
if (isset($struckture->parts[$key]->parts)) {
foreach ($struckture->parts[$key]->parts as $keyb => $valueb) {
$enc = $struckture->parts[$key]->parts[$keyb]->encoding;
if ($struckture->parts[$key]->parts[$keyb]->ifdparameters) {
//命名图片
$name = $this->decode_mime($struckture->parts[0]->parts[$keyb]->dparameters[0]->value);
$extend = explode(".", $name);
$file['extension'] = $extend[count($extend) - 1];
$file['pathname'] = $this->setPathName($mid,$key, $file['extension'],0);
$file['title'] = !empty($name) ? htmlspecialchars($name) : str_replace('.' . $file['extension'], '', $name);
// $file['size'] = $struckture->parts[$key]->parts[$keyb]->dparameters[1]->value;
// $file['tmpname'] = $struckture->parts[$key]->dparameters[0]->value;
$file['type'] = 0;
$partnro = ($key + 1) . "." . ($keyb + 1);
$message = imap_fetchbody($this->marubox, $mid, $partnro);
if ($enc == 0){
$message = imap_8bit($message);
}
if ($enc == 1){
$message = imap_8bit($message);
}
if ($enc == 2){
$message = imap_binary($message);
}
if ($enc == 3){
$message = imap_base64($message);
}
if ($enc == 4){
$message = quoted_printable_decode($message);
}
if ($enc == 5){
$message = $message;
}
$path = ROOT_PATH.'public' . DS . 'contentImg' . DS . date('Ymd') .DS;
if (!file_exists($path)){
mkdir($path,0777,true);
}
$fp = fopen($path . $file['pathname'], "w+");
fwrite($fp, $message);
fclose($fp);
$file['url']=$path . $file['pathname'];
$files[] = $file;
}
}
}
}
}
}
return $files;
}
/**
* 获取正文
* @param $mid
* @param $path
* @param $imageList
* @return false|mixed|string|string[]|void
*/
function getBody($mid,$path,$imageList,$section) // Get Message Body
{
if (!$this->marubox){
return false;
}
$struckture = imap_fetchstructure($this->marubox, $mid);
if(isset($struckture->parts))
{
if($struckture->subtype == 'MIXED' || $struckture->subtype == 'RELATED' ){
$encoding= $struckture->parts[0]->parts[0]->encoding;
}
if($struckture->subtype == 'ALTERNATIVE'){
$encoding = $struckture->parts[0]->encoding;
}
$body = $this->contentDecoder($encoding,$mid,$section);
//处理图片
$body = $this->embed_images($body, $path, $imageList);
return $body;
}
}
private function contentDecoder($encoding, $num,$section) //$this->mbox, $num, $section
{
switch ($encoding) {
case 0:
case 1:
$message = imap_8bit(imap_fetchbody($this->marubox, $num, $section));
break;
case 2:
$message = imap_binary(imap_fetchbody($this->marubox, $num, $section));
break;
case 3:
$message = iconv('gbk', 'utf-8',imap_base64(imap_fetchbody($this->marubox, $num, $section)));
break;
case 4:
$message = quoted_printable_decode(imap_fetchbody($this->marubox, $num, $section));
break;
}
return $message;
}
function embed_images(&$body,&$path,$imageList)
{
// get all img tags
preg_match_all('/<img.*?>/', $body, $matches);
if (!isset($matches[0])) return;
foreach ($matches[0] as $key=>$img)
{
// halt($path.$imageList[$key]);
// replace image web path with local path
preg_match('/src="(.*?)"/', $img, $m);
if (!isset($m[1])) continue;
$arr = parse_url($m[1]);
if (!isset($arr['scheme']) || !isset($arr['path']))continue;
// if (!isset($arr['host']) || !isset($arr['path']))continue;
if ($arr['scheme']!="http")
{
$filename=explode("@", $arr['path']);
$body = str_replace($img, '<img alt="" src="'.$path.$imageList[$key].'" style="border: none;" />', $body);
// $body = str_replace($img, '<img alt="" src="'.$path.$imageList[$filename[0]].'" style="border: none;" />', $body);
}
}
return $body;
}
function get_part($stream, $msg_number, $mime_type, $structure = false, $part_number = false) //Get Part Of Message Internal Private Use
{
if (!$structure) {
$structure = imap_fetchstructure($stream, $msg_number);
}
if ($structure) {
if ($mime_type == $this->get_mime_type($structure)) {
if (!$part_number) {
$part_number = "1";
}
$text = imap_fetchbody($stream, $msg_number, $part_number);
if ($structure->encoding == 3) {
return imap_base64($text);
// if ($structure->parameters[0]->value!="utf-8")
// {
// return imap_base64($text);
// }
// else
// {
// return imap_base64($text);
// }
} else if ($structure->encoding == 4) {
return iconv('gb2312', 'utf8', imap_qprint($text));
} else {
return iconv('gb2312', 'utf8', $text);
}
}
if ($structure->type == 1) /* multipart */ {
while (list($index, $sub_structure) = $this->new_each($structure->parts)) {
if ($part_number) {
$prefix = $part_number . '.';
}else{
$prefix = "1";
}
$data = $this->get_part($stream, $msg_number, $mime_type, $sub_structure, $prefix . ($index + 1));
if ($data) {
return $data;
}
}
}
}
return false;
}
function get_mime_type(&$structure) //Get Mime type Internal Private Use
{
$primary_mime_type = array("TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO", "OTHER");
if($structure->subtype && $structure->subtype!="PNG") {
return $primary_mime_type[(int) $structure->type] . '/' . $structure->subtype;
}
return "TEXT/PLAIN";
}
function new_each(&$array){
$res = array();
$key = key($array);
if($key !== null){
next($array);
$res[1] = $res['value'] = $array[$key];
$res[0] = $res['key'] = $key;
}else{
$res = false;
}
return $res;
}
/**
* 标题编码转化
* @param $str
* @return false|string
*/
function decode_mime($str)
{
$str = imap_mime_header_decode($str);
return $str[0]->text;
if ($str[0]->charset != "default") {
return iconv($str[0]->charset, 'utf8', $str[0]->text);
} else {
return $str[0]->text;
}
}
/**
* Set path name of the uploaded file to be saved.
*
* @param int $mid
* @param int $fileID
* @param string $extension
* @access public
* @return string
*/
public function setPathName($mid, $fileID, $extension,$type = 1)
{
if($type == 1){
return $mid."-".$fileID .'.' . $extension;
}else{
return $mid."-".$fileID .mt_rand(0, 10000) .'.' . $extension;
}
}
}