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

來源:互聯網
上載者:User
關鍵字 郵件 實現 編碼 MIME 部分 表示 本文 一個 解碼
POP3

MIME 編碼方式簡介
(作者:陳俊清 2000年10月24日 15:09)

  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,這樣就不存在只能傳輸 7bit 的字元的問題了。Base 64的縮寫一般是“B”,像這封信中的Subject 就是用的 Base 64 編碼。

  另一種方法是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 表示的是用的 Base 64 編碼。通過這段分析,我們來看一下這個 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 . $encoded_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 編程基礎的人都能夠看得明白。該函數也是調用的base64_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 表示的 Html 文檔,
image/gif 表示的是 gif 格式的圖片等等。

  在本文中特別要說明一下的是郵件中常用到的複合類型。multipart 類型表示本文是由多個部分組成的,後面的子類型說明的是這些部分之間的關係,郵件中用到的三個類型有,

multipart/alternative:表示本文由兩個部分組成,可以選擇其中的任意一個。主要作用是在徵文同時有 text 格式和 html 格式時,可以在兩個本文中選擇一個來顯示,支援 html 格式的郵件用戶端軟體一般會顯示其 HTML 本文,而不支援的則會顯示其 Text 本文;

multipart/mixed :表示文檔的多個部分是混合的,指本文與附件的關係。如果郵件的 MIME 類型是

multipart/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 來表示一個部分的開始,在文檔的結束,以"--"加boundary再在最後加上 "--" 來表示文檔的結束。由於複合類型是可以嵌套使用的,因此,郵件中可能會多個 boundary 。

  還有一個最重要的 MIME 頭標籤:

  Content-Transfer-Encoding: base64 它表示了這個部分文檔的編碼方式,也就是我們上面所介紹的Base64或QP(Quote-Printable)。我們只有識別了這個說明,才能用正確的解碼方式實現對其解碼。

  限於篇幅,對於 MIME 的介紹就只說到這裡。下面我將給出一個解碼MIME郵件的類,並對其做簡要說明。
  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.