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
在这里要特别说明一点的是html正文里所用图片的解码。发送html格式的正文时,都会碰到图片如何传送的问题。图片在 html 文档里是一个
的标签,关键是这个源文件从何来的。很多邮件的处理方法是用一个绝对的 url 标识,就是在邮件的html正文里用
之类的标签,这样,在阅读邮件时,邮件阅读器(通常是用内嵌的浏览器)会自动从网上下载图片,但是如果邮件收下来之后,与 的连接断了,图片也就不能正常显示。
所以更好的方法是把图片放在邮件中一起发送出去。在 MIME 编码里,描述图片与正文的关系,除了上面所提到的multipart/related MIME头信息之外,还用到了一个 Content-ID: 的属性来使图片与 html 正文之间建立关系。html 文档中的图片在编码时,其MIME头中加入一个 Content-ID:122223443556dsdf@ntsever 之类的属性,122223443556dsdf@ntsever是一个唯一的标识,在 html 文档里,
标签被修改成
,在解码的时候,实际上,还需要把 html 正文中的这些
标签进行修改,使之指向解码后的图片的具体路径。但是考虑到具体的解码程序中对图片会有不同的处理,所以在这个解码的类中,没有对 hmtl 正文中的
标签进行修改。所以在实际使用这个类时,对于有图片的 html 正文,还需要一定的处理。正文中的图片,可以用临时文件来保存,也可以用来保存。
现在我们已经介绍了POP3 收取邮件并进行 MIME 解码的原理。下面给出一个使用这两个类的一段小程序:
include("pop3.inc.php");
include("mime.inc.php");
$host="pop.china.com";
$user="boss_ch";
$pass="mypassword";
$rec=new pop3($host,110,2);
$decoder=new decode_mail();
if (!$rec->open()) die($rec->err_str);
if (!$rec->login($user,$pass)) die($rec->err_str);
if (!$rec->stat()) die($rec->err_str);
echo "共有".$rec->messages."封信件,共".$rec->size."字节大小
";
if ($rec->messages>0)
{
if (!$rec->listmail()) die($rec->err_str);
echo "以下是信件内容:
";
for ($i=1;$i<=count($rec->mail_list);$i++)
{
echo "信件".$rec->mail_list[$i][num].",大小:".$rec->mail_list[$i][size]."
";
$rec->getmail($rec->mail_list[$i][num]);
$decoder->decode($rec->head,$rec->body);
echo "
邮件头的内容:
";
echo $decoder->from_name."(".$decoder->from_mail.") 于".date("Y-m-d H:i:s",$decoder->mail_time)." 发给".$decoder->to_name."(".$decoder->to_mail.")";
echo "\n
抄送:";
if ($decoder->cc_to) echo $decoder->cc_to;else echo "无";
echo "\n
主题:".$decoder->subject;