请教一下高手MIME编码 看以下RFC文档RFC 2045, RFC 2046, RFC 2047, RFC 2048, RFC 2049 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 sxbyl(白菜)我对RFC所至甚少! MIME 编码方式简介 Subject: =?gb2312?B?xOO6w6Oh?= 这里是邮件的主题,可是因为编码了,我们看不出是什么内容,其原来的文本是: “你好!”我们先看看 MIME 编码的两种方法。 对邮件进行编码最初的原因是因为 Internet 上的很多网关不能正确传输8 bit 内 码的字符,比如汉字等。编码的原理就是把 8 bit 的内容转换成 7 bit 的形式以能正 确传输,在接收方收到之后,再将其还原成 8 bit 的内容。 MIME 是“多用途网际邮件扩充协议”的缩写,在 MIME 协议之前,邮件的编码曾经 有过 UUENCODE 等编码方式 ,但是由于 MIME 协议算法简单,并且易于扩展,现在已经 成为邮件编码方式的主流,不仅是用来传输 8 bit 的字符,也可以用来传送二进制的文 件 ,如邮件附件中的图像、音频等信息,而且扩展了很多基于MIME 的应用。从编码方 式来说,MIME 定义了两种编码方法Base64与QP(Quote-Printable) : Base 64 是一种通用的方法,其原理很简单,就是把三个Byte的数据用 4 个Byte表 示,这样,这四个Byte 中,实际用到的都只有前面6 bit,这样就不存在只能传输 7bi t 的字符的问题了。Base 64的缩写一般是“B”,像这封信中的Subject 就是用的 Bas e64 编码。 另一种方法是QP(Quote-Printable) 方法,通常缩写为“Q”方法,其原理是把一个 8 bit 的字符用两个16进制数值表示,然后在前面加“=”。所以我们看到经过QP编码 后的文件通常是这个样子:=B3=C2=BF=A1=C7=E5=A3=AC=C4=FA=BA=C3=A3=A1。 在 PHP 里,系统有两个函数可以很方便地实现解码:base64_decode()与quoted _printable_decode(),前者可用于base64 编码的解码,后者是用于 QP 编码方法的 解码。 现在我们再来看看Subject: =?gb2312?B?xOO6w6Oh?= 这一主题的内容,这不是一段 完整的编码,只有部分是编码了的,这个部分用 =? ?= 两个标记括起来,=? 后面说明 的是这段文字的字符集是 GB2312 ,然后一个 ? 后面的一个 B 表示的是用的 Base64 编码。通过这段分析,我们来看一下这个 MIME 解码的函数:(该函数由 PHPX.COM 站 长 Sadly 提供,本人将其放入一个类中,并做了少量的修改,在此致谢) function decode_mime($string) { $pos = strpos($string, '=?'); if (!is_int($pos)) { return $string; } $preceding = substr($string, 0, $pos); // save any preceding text $search = substr($string, $pos+2); /* the mime header spec says this is the longest a single encoded word can be */ $d1 = strpos($search, '?'); if (!is_int($d1)) { return $string; } $charset = substr($string, $pos+2, $d1); //取出字符集的定义部分 $search = substr($search, $d1+1); //字符集定义以后的部分=>$search; $d2 = strpos($search, '?'); if (!is_int($d2)) { return $string; } $encoding = substr($search, 0, $d2); ////两个? 之间的部分编码方式 :q 或 b $search = substr($search, $d2+1); $end = strpos($search, '?='); //$d2+1 与 $end 之间是编码了 的内容:=> $endcoded_text; if (!is_int($end)) { return $string; } $encoded_text = substr($search, 0, $end); $rest = substr($string, (strlen($preceding . $charset . $encoding . $en coded_text)+6)); //+6 是前面去掉的 =????= 六个字符 switch ($encoding) { case 'Q': case 'q': //$encoded_text = str_replace('_', '%20', $encoded_text); //$encoded_text = str_replace('=', '%', $encoded_text); //$decoded = urldecode($encoded_text); $decoded=quoted_printable_decode($encoded_text); if (strtolower($charset) == 'windows-1251') { $decoded = convert_cyr_string($decoded, 'w', 'k'); } break; case 'B': case 'b': $decoded = base64_decode($encoded_text); if (strtolower($charset) == 'windows-1251') { $decoded = convert_cyr_string($decoded, 'w', 'k'); } break; default: $decoded = '=?' . $charset . '?' . $encoding . '?' . $encoded_text . '?='; break; } return $preceding . $decoded . $this->decode_mime($rest); } 这个函数用了递归的方法来实现一段包含有如上的 Subject 段的字符的解码。程序 中已经加上了注释。相信有点PHP 编程基础的人都能够看得明白。该函数也是调用的ba se64_decode()与quoted_printable_decode()两个系统函数实现的解码,但是需要 对邮件源文件进行大量的字符串的分析。不过,PHP 的字符串操作可以算是所有语言里 最为方便自由的。函数的最后return $preceding . $decoded . $this->decode_mime( $rest); 实现递归解码,因为这个函数实际上是放在后面要介绍的一个 MIME解码的类中 的,所以用了 $this->decode_mime($rest)这种形式的调用方法。 下面我们来看正文。这里关系到 MIME 的一些头信息,我们先做一个简单的介绍( 如果读者有兴趣了解更多的内容,请参考 MIME 的官方文档)。 MIME-Version: 1.0 表示使用的 MIME 的版本号,一般是1.0; Content-Type: 定义了正文的类型,我们实际上是通过这个标识来知道正文内是什 么类型的文件,比如:text/plain 表示的是无格式的文本正文,text/html 表示的 Ht ml 文档,image/gif 表示的是 gif 格式的图片等等。在本文中特别要说明一下的是邮 件中常用到的复合类型。multipart 类型表示正文是由多个部分组成的,后面的子类型 说明的是这些部分之间的关系,邮件中用到的三个类型有,multipart/alternative:表 示正文由两个部分组成,可以选择其中的任意一个。主要作用是在征文同时有 text 格 式和 html 格式时,可以在两个正文中选择一个来显示,支持 html 格式的邮件客户端 软件一般会显示其 HTML 正文,而不支持的则会显示其 Text 正文;multipart/mixed :表示文档的多个部分是混合的,指正文与附件的关系。如果邮件的 MIME 类型是mult ipart/mixed,即表示邮件带有附件;multipart/related :表示文档的多个部分是相关 的,一般用来描述 Html 正文与其相关的图片。 这些复合类型又是可以嵌套使用的,比如说一个带有附件的邮件,同时有 html 与 text 两种格式的正文,则邮件的结构是: Content-Type: multipart/mixed 部分一: Content Type : multipart/alternative: Text 正文; Html 格式的正文 部分二: 附件 邮件结束符; 由于复合类型由多个部分组成,因此,需要一个分隔符来分隔这多个部分,这就是 上面的邮件源文件中的boundary="----=_NextPart_000_0007_01C03166.5B1E9510"所描 述的,对于每一个Contect type :multipart/* 的内容,都会有这么一个说明,表示多 个部分之间的分隔,这个分隔符是正文中不可能出现的一串古字符的组合,在文档中, 以 "--" 加上这个boundary 来表示一个部分的开始,在文档的结束,以"--"加bounda ry再在最后加上 "--" 来表示文档的结束。由于复合类型是可以嵌套使用的,因此,邮 件中可能会多个 boundary 。 还有一个最重要的 MIME 头标签: Content-Transfer-Encoding: base64 它表示了这个部分文档的编码方式,也就是 我们上面所介绍的Base64或QP(Quote-Printable)。我们只有识别了这个说明,才能用正 确的解码方式实现对其解码。 限于篇幅,对于 MIME 的介绍就只说到这里。下面我将给出一个解码MIME邮件的类, 并对其做简要说明。 怎么使用JavaScript调用mfc中的方法 函数参数个数不定,使用时出现如下错误怎么解决 求技术文档编写规范 请问用vb开发的控件JanChart 能否在mfc中使用 明天相亲,高兴,散分 100 分求《Progamming Applications》电子书 怎么在不支持MFC的情况下,最好是用API,用PICTURE控件显示JPG图片? 用Ole DB如何连接sybase? 菜单栏读取序列化文件的问题 vc6里怎样从一个空project白手起家啊,帮忙看一下吧? 送分了(问题太简单了,可我不会) 用fopen打开文件,如何知道打开失败的详细原因?说者都有分。
我对RFC所至甚少!
这里是邮件的主题,可是因为编码了,我们看不出是什么内容,其原来的文本是:
“你好!”我们先看看 MIME 编码的两种方法。
对邮件进行编码最初的原因是因为 Internet 上的很多网关不能正确传输8 bit 内
码的字符,比如汉字等。编码的原理就是把 8 bit 的内容转换成 7 bit 的形式以能正
确传输,在接收方收到之后,再将其还原成 8 bit 的内容。
MIME 是“多用途网际邮件扩充协议”的缩写,在 MIME 协议之前,邮件的编码曾经
有过 UUENCODE 等编码方式 ,但是由于 MIME 协议算法简单,并且易于扩展,现在已经
成为邮件编码方式的主流,不仅是用来传输 8 bit 的字符,也可以用来传送二进制的文
件 ,如邮件附件中的图像、音频等信息,而且扩展了很多基于MIME 的应用。从编码方
式来说,MIME 定义了两种编码方法Base64与QP(Quote-Printable) :
Base 64 是一种通用的方法,其原理很简单,就是把三个Byte的数据用 4 个Byte表
示,这样,这四个Byte 中,实际用到的都只有前面6 bit,这样就不存在只能传输 7bi
t 的字符的问题了。Base 64的缩写一般是“B”,像这封信中的Subject 就是用的 Bas
e64 编码。
另一种方法是QP(Quote-Printable) 方法,通常缩写为“Q”方法,其原理是把一个
8 bit 的字符用两个16进制数值表示,然后在前面加“=”。所以我们看到经过QP编码
后的文件通常是这个样子:=B3=C2=BF=A1=C7=E5=A3=AC=C4=FA=BA=C3=A3=A1。
在 PHP 里,系统有两个函数可以很方便地实现解码:base64_decode()与quoted
_printable_decode(),前者可用于base64 编码的解码,后者是用于 QP 编码方法的
解码。
现在我们再来看看Subject: =?gb2312?B?xOO6w6Oh?= 这一主题的内容,这不是一段
完整的编码,只有部分是编码了的,这个部分用 =? ?= 两个标记括起来,=? 后面说明
的是这段文字的字符集是 GB2312 ,然后一个 ? 后面的一个 B 表示的是用的 Base64
编码。通过这段分析,我们来看一下这个 MIME 解码的函数:(该函数由 PHPX.COM 站
长 Sadly 提供,本人将其放入一个类中,并做了少量的修改,在此致谢)
function decode_mime($string) {
$pos = strpos($string, '=?');
if (!is_int($pos)) {
return $string;
}
$preceding = substr($string, 0, $pos); // save any preceding text
$search = substr($string, $pos+2); /* the mime header spec says this is
the longest a single encoded word can be */
$d1 = strpos($search, '?');
if (!is_int($d1)) {
return $string;
}
$charset = substr($string, $pos+2, $d1); //取出字符集的定义部分
$search = substr($search, $d1+1); //字符集定义以后的部分=>$search;
$d2 = strpos($search, '?');
if (!is_int($d2)) {
return $string;
}
$encoding = substr($search, 0, $d2); ////两个? 之间的部分编码方式 :q
或 b
$search = substr($search, $d2+1);
$end = strpos($search, '?='); //$d2+1 与 $end 之间是编码了 的内容:=>
$endcoded_text;
if (!is_int($end)) {
return $string;
}
$encoded_text = substr($search, 0, $end);
$rest = substr($string, (strlen($preceding . $charset . $encoding . $en
coded_text)+6)); //+6 是前面去掉的 =????= 六个字符
switch ($encoding) {
case 'Q':
case 'q':
//$encoded_text = str_replace('_', '%20', $encoded_text);
//$encoded_text = str_replace('=', '%', $encoded_text);
//$decoded = urldecode($encoded_text);
$decoded=quoted_printable_decode($encoded_text);
if (strtolower($charset) == 'windows-1251') {
$decoded = convert_cyr_string($decoded, 'w', 'k');
}
break;
case 'B':
case 'b':
$decoded = base64_decode($encoded_text);
if (strtolower($charset) == 'windows-1251') {
$decoded = convert_cyr_string($decoded, 'w', 'k');
}
break;
default:
$decoded = '=?' . $charset . '?' . $encoding . '?' . $encoded_text
. '?=';
break;
}
return $preceding . $decoded . $this->decode_mime($rest);
}
这个函数用了递归的方法来实现一段包含有如上的 Subject 段的字符的解码。程序
中已经加上了注释。相信有点PHP 编程基础的人都能够看得明白。该函数也是调用的ba
se64_decode()与quoted_printable_decode()两个系统函数实现的解码,但是需要
对邮件源文件进行大量的字符串的分析。不过,PHP 的字符串操作可以算是所有语言里
最为方便自由的。函数的最后return $preceding . $decoded . $this->decode_mime(
$rest); 实现递归解码,因为这个函数实际上是放在后面要介绍的一个 MIME解码的类中
的,所以用了 $this->decode_mime($rest)这种形式的调用方法。
下面我们来看正文。这里关系到 MIME 的一些头信息,我们先做一个简单的介绍(
如果读者有兴趣了解更多的内容,请参考 MIME 的官方文档)。
MIME-Version: 1.0
表示使用的 MIME 的版本号,一般是1.0;
Content-Type: 定义了正文的类型,我们实际上是通过这个标识来知道正文内是什
么类型的文件,比如:text/plain 表示的是无格式的文本正文,text/html 表示的 Ht
ml 文档,image/gif 表示的是 gif 格式的图片等等。在本文中特别要说明一下的是邮
件中常用到的复合类型。multipart 类型表示正文是由多个部分组成的,后面的子类型
说明的是这些部分之间的关系,邮件中用到的三个类型有,multipart/alternative:表
示正文由两个部分组成,可以选择其中的任意一个。主要作用是在征文同时有 text 格
式和 html 格式时,可以在两个正文中选择一个来显示,支持 html 格式的邮件客户端
软件一般会显示其 HTML 正文,而不支持的则会显示其 Text 正文;multipart/mixed
:表示文档的多个部分是混合的,指正文与附件的关系。如果邮件的 MIME 类型是mult
ipart/mixed,即表示邮件带有附件;multipart/related :表示文档的多个部分是相关
的,一般用来描述 Html 正文与其相关的图片。
这些复合类型又是可以嵌套使用的,比如说一个带有附件的邮件,同时有 html 与
text 两种格式的正文,则邮件的结构是:
Content-Type: multipart/mixed
部分一:
Content Type : multipart/alternative:
Text 正文;
Html 格式的正文
部分二:
附件
邮件结束符;
由于复合类型由多个部分组成,因此,需要一个分隔符来分隔这多个部分,这就是
上面的邮件源文件中的boundary="----=_NextPart_000_0007_01C03166.5B1E9510"所描
述的,对于每一个Contect type :multipart/* 的内容,都会有这么一个说明,表示多
个部分之间的分隔,这个分隔符是正文中不可能出现的一串古字符的组合,在文档中,
以 "--" 加上这个boundary 来表示一个部分的开始,在文档的结束,以"--"加bounda
ry再在最后加上 "--" 来表示文档的结束。由于复合类型是可以嵌套使用的,因此,邮
件中可能会多个 boundary 。
还有一个最重要的 MIME 头标签:
Content-Transfer-Encoding: base64 它表示了这个部分文档的编码方式,也就是
我们上面所介绍的Base64或QP(Quote-Printable)。我们只有识别了这个说明,才能用正
确的解码方式实现对其解码。
限于篇幅,对于 MIME 的介绍就只说到这里。下面我将给出一个解码MIME邮件的类,
并对其做简要说明。