程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> 用PHP實現POP3郵件的解碼(三)

用PHP實現POP3郵件的解碼(三)

編輯:PHP綜合

實現 MIME 解碼的類

該類實現解碼的方法是 decode($head=null,$body=null,$content_num=-1),為了處理上的方便,要求輸入的是兩個字符數組,在我們的上篇中,所用到的POP類所收取得到的就是兩個這樣的數組,一個是郵件頭內容,一個是郵件的正文內容。限於篇幅,不對其做詳細的說明,其實現思想跟本文上篇中所介紹的POP類類似。請參考其中的注釋。

該類中用到了大量的正則表達式的操作,對此不熟悉的讀者,請參考正則表達式的有關資料。

class decode_mail
{
var $from_name;var $to_name;var $mail_time;var $from_mail;var $to_mail;
var $reply_to;var $cc_to;var $subject;
// 解碼後的郵件頭部分的信息:
var $body;
// 解碼後得到的正文數據,為一個數組。
var $body_type; // 正文類型
var $tem_num=0;
var $get_content_num=0;
var $body_temp=array();
var $body_code_type;
var $boundary;
// 以上是一些方法中用到的一些全局性的臨時變量,由於 php不能做到良好的封裝,所以只能放在這裡定義
var $err_str; // 錯誤信息
var $debug=0; // 調試標記
var $month_num=array("Jan"=>1,"Feb"=>2,"Mar"=>3,"APR"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,
"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12); // 把英文月份轉換成數字表示的月份
function decode($head=null,$body=null,$content_num=-1) // 調用的主方法,$head 與 $body 是兩個數組,$content_num 表示的是當正文有多個部分的時候,只取出指定部分的內容以提高效率,默認為 -1 ,表示解碼全部內容,如果解碼成功,該 方法返回 true
{
if (!$head and !$body)
{
$this->err_str="沒有指定郵件的頭與內容!!";
return false;
}
if (gettype($head)=="array")
{
$have_decode=true;
$this->decode_head($head);
}
if (gettype($body)=="array")
{
$this->get_content_num=$content_num;
$this->body_temp=$body;
$have_decode=true;
$this->decode_body();
unset($this->body_temp);
}
if (!$have_decode)
{
$this->err_str="傳遞的參數不對,用法:new decode_mail(head,body) 兩個參數都是數組";
return false;
}
}
function decode_head($head) // 郵件頭內容 的解碼,取出郵件頭中有意義的內容
{
$i=0;
$this->from_name=$this->to_name=$this->mail_time=$this->from_mail=$this->
to_mail=$this->reply_to=$this->cc_to=$this->subject="";
$this->body_type=$Sthis->boundary=$this->body_code_type="";
while ($head[$i])
{
if (strpos($head[$i],"=?"))
$head[$i]=$this->decode_mime($head[$i]);  //如果有編碼的內容,則進行解碼,解碼函數是上文所介紹的 decode_mime()
$pos=strpos($head[$i],":");
$summ=substr($head[$i],0,$pos);
$content=substr($head[$i],$pos+1);  //將郵件頭信息的標識與內容分開
if ($this->debug) echo $summ.":----:".$content."<BR>";
switch (strtoupper($summ))
{
case "FROM": // 發件人地址及姓名(可能沒有姓名,只有地址信息)
if ($left_tag_pos=strpos($content,"<"))
{
$mail_lenth=strrpos($content,">")-$left_tag_pos-1;
$this->from_name=substr($content,0,$left_tag_pos);
$this->from_mail=substr($content,$left_tag_pos+1,$mail_lenth);
if (trim($this->from_name)=="") $this->from_name=$this->from_mail;
else
if (ereg("[\"|\']([^\'\"]+)[\'|\"]",$this->from_name,$reg))
$this->from_name=$reg[1];
}
else
{
$this->from_name=$content;
$this->from_mail=$content;
//沒有發件人的郵件地址
}
break;
case "TO": //收件人地址及姓名(可能 沒有姓名)
if ($left_tag_pos=strpos($content,"<"))
{
$mail_lenth=strrpos($content,">")-$left_tag_pos-1;
$this->to_name=substr($content,0,$left_tag_pos);
$this->to_mail=substr($content,$left_tag_pos+1,$mail_lenth);
if (trim($this->to_name)=="") $this->to_name=$this->to_mail;
else
if (ereg("[\"|\']([^\'\"]+)[\'|\"]",$this->to_name,$reg))
$this->to_name=$reg[1];
}
else
{
$this->to_name=$content;
$this->to_mail=$content;
//沒有分開收件人的郵件地址
}
break;
case "DATE" : //發送日期,為了處理方便,這裡返回的是一個 Unix 時間戳,可以用 date("Y-m-d",$this->mail_time) 來得到一般格式的日期
$content=trim($content);
$day=strtok($content," ");
$day=substr($day,0,strlen($day)-1);
$date=strtok(" ");
$month=$this->month_num[strtok(" ")];
$year=strtok(" ");
$time=strtok(" ");
$time=split(":",$time);
$this->mail_time=mktime($time[0],$time[1],$time[2],$month,$date,$year);
break;
case "SUBJECT":  //郵件主題
$this->subject=$content;
break;
case "REPLY_TO": // 回復地址(可能沒有)
if (ereg("<([^>]+)>",$content,$reg))
$this->reply_to=$reg[1];
else $this->reply_to=$content;
break;
case "CONTENT-TYPE": // 整個郵件的 Content類型, eregi("([^;]*);",$content,$reg);
$this->body_type=trim($reg[1]);
if (eregi("multipart",$content)) // 如果是 multipart 類型,取得 分隔符
{
while (!eregi('boundary=\"(.*)\"',$head[$i],$reg) and $head[$i])
$i++;
$this->boundary=$reg[1];
}
else //對於一般的正文類型,直接取得其編碼方法
{
while (!eregi("charset=[\"|\'](.*)[\'|\"]",$head[$i],$reg))
$i++;
$this->body_char_set=$reg[1];
while (!eregi("Content-Transfer-Encoding:(.*)",$head[$i],$reg))
$i++;
$this->body_code_type=trim($reg[1]);
}
break;
case "CC": //抄送到。。
if (ereg("<([^>]+)>",$content,$reg))
$this->cc_to=$reg[1];
else
$this->cc_to=$content;
default:
break;
} // end switch

$i++;
} // end while

if (trim($this->reply_to)=="")  //如果沒有指定回復地址,則回復地址為發送人地址
$this->reply_to=$this->from_mail;
}// end function define
function decode_body() //正文的解碼,其中用到了不少郵件頭解碼所得來的信息
{
$i=0;
if (!eregi("multipart",$this->body_type)) // 如果不是復合類型,可以直接解碼
{
$tem_body=implode($this->body_temp,"\r\n");
switch (strtolower($this->body_code_type)) // body_code_type ,正文的編碼方式,由郵件頭信息中取得
{case "base64":
$tem_body=base64_decode($tem_body);
break;
case "quoted-printable":
$tem_body=quoted_printable_decode($tem_body);
break;
}
$this->tem_num=0;
$this->body=array();
$this->body[$this->tem_num][content_id]="";
$this->body[$this->tem_num][type]=$this->body_type;
switch (strtolower($this->body_type))
{
case "text/html":
$this->body[$this->tem_num][name]="超文本正文";
break;
case "text/plain":
$this->body[$this->tem_num][name]="文本正文";
break;
default:
$this->body[$this->tem_num][name]="未知正文";
}

$this->body[$this->tem_num][size]=strlen($tem_body);
$this->body[$this->tem_num][content]=$tem_body;
unset($tem_body);
}
else // 如果是復合類型的
{
$this->body=array();
$this->tem_num=0;
$this->decode_mult($this->body_type,$this->boundary,0);  //調用復合類型的解碼方法
}
}
function decode_mult($type,$boundary,$begin_row) // 該方法用遞歸的方法實現 復合類型郵件正文的解碼,郵件源文件取自於 body_temp 數組,調用時給出該復合類型的類型、分隔符及 在 body_temp 數組中的開始指針
{
$i=$begin_row;
$lines=count($this->body_temp);
while ($i<$lines) // 這是一個部分的結束標識;
{
while (!eregi($boundary,$this->body_temp[$i]))//找到一個開始標識
$i++;
if (eregi($boundary."--",$this->body_temp[$i]))
{
return $i;
}
while (!eregi("Content-Type:([^;]*);",$this->body_temp[$i],$reg ) and $this->body_temp[$i])
$i++;
$sub_type=trim($reg[1]); // 取得這一個部分的 類型是milt or text ....
if (eregi("multipart",$sub_type))// 該子部分又是有多個部分的;
{
while (!eregi('boundary=\"([^\"]*)\"',$this->body_temp[$i],$reg) and $this->body_temp[$i])
$i++;
$sub_boundary=$reg[1];// 子部分的分隔符;
$i++;
$last_row=$this->decode_mult($sub_type,$sub_boundary,$i);
$i=$last_row;
}
else
{
$comm="";
while (trim($this->body_temp[$i])!="")
{
if (strpos($this->body_temp[$i],"=?"))
$this->body_temp[$i]=$this->decode_mime($this->body_temp[$i]);
if (eregi("Content-Transfer-Encoding:(.*)",$this->body_temp[$i],$reg))
$code_type=strtolower(trim($reg[1])); // 編碼方式
$comm.=$this->body_temp[$i]."\r\n";
$i++;
} // comm 是編碼的說明部分
if (eregi('name=[\"]([^\"]*)[\"]',$comm,$reg))
$name=$reg[1];
if (eregi("Content-Disposition:(.*);",$comm,$reg))
$disp=$reg[1];
if (eregi("charset=[\"|\'](.*)[\'|\"]",$comm,$reg))
$char_set=$reg[1];
if (eregi("Content-ID:[ ]*\<(.*)\>",$comm,$reg)) // 圖片的標識符。
$content_id=$reg[1];
$this->body[$this->tem_num][type]=$sub_type;
$this->body[$this->tem_num][content_id]=$content_id;
$this->body[$this->tem_num][char_set]=$char_set;
if ($name)
$this->body[$this->tem_num][name]=$name;
else
switch (strtolower($sub_type))
{
case "text/html":
$this->body[$this->tem_num][name]="超文本正文";
break;
case "text/plain":
$this->body[$this->tem_num][name]="文本正文";
break;
default:
$this->body[$this->tem_num][name]="未知正文";
}  

// 下一行開始取回正文
if ($this->get_content_num==-1 or $this->get_content_num==$this->tem_num) // 判斷這個部分是否是需要的。-1 表示全部
{
$content="";
while (!ereg($boundary,$this->body_temp[$i]))
{
//$content[]=$this->body_temp[$i];
$content.=$this->body_temp[$i]."\r\n";
$i++;
}
//$content=implode("\r\n",$content);
switch ($code_type)
{
case "base64":
$content=base64_decode($content);
break;
case "quoted-printable":
$content=str_replace("\n","\r\n",quoted_printable_decode($content));
break;
}
$this->body[$this->tem_num][size]=strlen($content);
$this->body[$this->tem_num][content]=$content;
}
else
{
while (!ereg($boundary,$this->body_temp[$i]))
$i++;
}
$this->tem_num++;
}
// end else
} // end while;
} // end function define
function decode_mime($string) {
//decode_mime 已在上文中給出,這裡略過。
}
} // end class define

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved