電子郵件標頭 (Subject、From 等) 常包含 MIME 編碼文字以支援非 ASCII 字元。本文提供完整的 PHP 解碼函數,支援 Q (Quoted-Printable) 與 B (Base64) 兩種編碼,並處理 Big5/GB2312 等中文編碼轉換。
<?php
function decode_mime_string(string $string): string {
// 尋找 MIME 編碼標記開頭 =?
$pos = strpos($string, '=?');
if ($pos === false) return $string; // 無編碼段落
$preceding = substr($string, 0, $pos); // 前綴純文字
$search = substr($string, $pos + 2); // 剩餘部分
// 解析 charset (最長 75 字元依 RFC 2047)
$d1 = strpos($search, '?');
if ($d1 === false) return $string;
$charset = substr($search, 0, $d1);
$search = substr($search, $d1 + 1);
// 解析 encoding (Q 或 B)
$d2 = strpos($search, '?');
if ($d2 === false) return $string;
$encoding = strtoupper(substr($search, 0, $d2));
$search = substr($search, $d2 + 1);
// 解析編碼文字 (以 ?= 結尾)
$end = strpos($search, '?=');
if ($end === false) return $string;
$encoded_text = substr($search, 0, $end);
$rest = substr($string, $pos + 2 + strlen($charset) + 1 + strlen($encoding) + 1 + $end + 2);
// 解碼處理
switch ($encoding) {
case 'Q': // Quoted-Printable
$encoded_text = str_replace('_', ' ', $encoded_text); // _ 代表空格
$encoded_text = str_replace('=', '%', $encoded_text); // =XX -> %XX
$decoded = urldecode($encoded_text);
break;
case 'B': // Base64
$decoded = base64_decode($encoded_text);
break;
default:
// 未知編碼保持原樣
return $preceding . '=?' . $charset . '?' . $encoding . '?' . $encoded_text . '?=' . decode_mime_string($rest);
}
// 中文編碼轉換 (舊系統相容)
if (strtolower($charset) === 'big5' || strtolower($charset) === 'gb2312') {
// PHP 7.3+ 使用 mb_convert_encoding 替代已移除的 convert_cyr_string
if (function_exists('mb_convert_encoding')) {
$decoded = mb_convert_encoding($decoded, 'UTF-8', strtoupper($charset));
}
}
// 遞歸處理剩餘部分 (一個標頭可能包含多個編碼段落)
return $preceding . $decoded . decode_mime_string($rest);
}
// 使用範例
$subject = '=?UTF-8?B?5bCP56uL5LqO?= =?UTF-8?Q?=E6=B5=8B=E8=AF=95?=';
echo decode_mime_string($subject); // 輸出: 測試 測試
?>
Encoded-word = "=?" charset "?" encoding "?" encoded-text "?=" charset = 註冊字集名稱 (UTF-8, Big5, GB2312, ISO-8859-1...) encoding = "Q" / "B" (不分大小寫) encoded-text = 編碼後文字 (Q: =XX 格式, B: Base64) 最大長度 = 75 字元 (含 =? ?= 標記)
| 特性 | Q 編碼 (Quoted-Printable) | B 編碼 (Base64) |
|---|---|---|
| 適用場景 | 以 ASCII 為主、少量非 ASCII 字元 | 大量非 ASCII 字元 (中文、日文等) |
| 空格表示 | 底線 _ | Base64 標準編碼 |
| 特殊字元 | =XX (十六進位) | Base64 字元集 (A-Z,a-z,0-9,+,/) |
| 長度膨脹 | ~1-3 倍 | ~1.33 倍 |
| 可讀性 | 部分可讀 | 完全不可讀 |
PHP 5.3+ 提供
iconv_mime_decode()與mb_decode_mimeheader()內建函數,強烈建議優先使用:<?php // 完整標頭行解碼 $header = "Subject: =?UTF-8?B?5bCP56uL?= =?UTF-8?Q?=E6=B5=8B=E8=AF=95?="; echo iconv_mime_decode($header, 0, 'UTF-8'); // 輸出: Subject: 測試 測試 // 僅解碼 MIME 編碼字串 $encoded = '=?UTF-8?B?5bCP56uL?='; echo mb_decode_mimeheader($encoded); // 輸出: 測試 ?>優勢**:標準庫實作、自動處理多段落、支援所有 IANA 字集、效能優化、無維護負擔。
<?php
// 使用成熟庫而非手工解析
require 'vendor/autoload.php';
use MimeMailParser\Parser;
$parser = new Parser();
$parser->setText($rawEmail);
$subject = $parser->getHeader('subject'); // 自動解碼
$from = $parser->getHeader('from');
$bodyText = $parser->getMessageBody('text');
$bodyHtml = $parser->getMessageBody('html');
$attachments = $parser->getAttachments();
?>
php-mime-mail-parser/php-mime-mail-parser (Composer 安裝)