最近更新: 2007-04-13

PHP mail() and charset encoding question, part2 - mbstring

part1 中提到 mail() 會固定對信件內容進行編碼,而解決之道是改用 PHPMailer, PEAR::Mail 寄送信件。而本文則要繼續探索 mail() 對信件內容編碼之原因。

在一次測試過程中,我很偶然地、不小心地,打錯了 $headersContent-type 的字元集(charset)之值,結果找到 mail() 寄信會造成亂碼的原因。

下例將故意字元集之值故意輸入成 'utf-X' (請將範例程式碼以 UTF-8 編碼格式儲存)。

<?php
$mailTo = 'your@example.com'; // 請自行替換有效的收件地址
$message = 'test 測試';
$subject = 'TEST 測試';
$headers = 'Content-type: text/plain; charset=utf-X' . "\r\n";
$headers .= 'From: my@example.com' . "\r\n"; // 請自行替換寄件地址
mail($mailTo, $subject, $message, $headers);
?>

結果 PHP 顯示了一則警告訊息,如下所示:

Warning: mb_send_mail(): 
Unsupported charset "utf-X" - will be regarded as ascii in ...

這下我明白了,凶手就是 mb_send_mail()。原來 mail() 實際上已經被 mb_send_mail() 覆寫了,而 mb_send_mail() 會判讀 header 內容對信件內容編碼。這正是造成亂碼的原因。

我直覺想到這與 mbstring extension 有關。只要不載入 mbstring extension 或是在 php.ini 中設定 mbstring.func_overload = 6(not overload mail()),那麼問題便可迎刃而解。我測試後確實可解,取消 mbstring.func_overloadmail() 之覆寫動作後, mail() 的行為跟以前一樣,不會對信件內容亂編碼。

但在實務上,有不少人是租用虛擬主機空間運行 PHP 程式。而那些虛擬主機供應商不可能允許用戶自行修改 php.ini 之內容。所以此處的解決方式不適合虛擬主機用戶,他們應採用 part1 的解決方式。

樂多舊網址: http://blog.roodo.com/rocksaying/archives/2998451.html

樂多舊回應
meluwu@xuite.net(melu) (#comment-16224163)
Tue, 15 Apr 2008 09:59:10 +0800
請問一下當我用像下面的程式去跑的時侯為什麼在信件的本文的部份常會莫名的跑出!或亂碼...本文部份是讀入utf8格式的中文字..是那個部份 下錯 了嗎 ??謝 謝
$subj='=?utf-8?B?' . base64_encode("中文測試").'?=';
$to = 'melu@yahoo.com';
$from = '英文';
$mime = md5(uniqid(mt_rand(),TRUE));

$header = "From:=?utf-8?B?".base64_encode($from)."?=\r\n";
$header .= "MIME-Version:1.0\r\n";
$header .= "Content-Type: multipart/alternative;boundary=".$mime."\r\n";
$header .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
$msg="";
$msg .= "--".$mime."\r\n";
$msg .= "Content-Type: text/plain; charset=UTF-8\n";
$msg .= "Content-Transfer-Encoding: 8bit\n\n";
$msg .= "--".$mime."\r\n";
$msg .= "Content-Type: text/html; charset=UTF-8\n";
$msg .= "Content-Transfer-Encoding: 8bit\n\n";///////////////////////////
//--------------------------
$msgbody="";
$msgbody.="";
$msgbody.="";
$msgbody.="";
$msgbody.="";
$msgbody.="";
$msgbody.=" ";
$msgbody.=" 中文測試";
$msgbody.=" ";
$msgbody.="";
$msgbody.="";

$data = $msgbody;
$msg .= $data."\r\n";
$msg .= "--".$mime."--\r\n";
mb_internal_encoding("UTF-8");

mb_send_mail($to, $subj, $msg, $header);
未留名 (#comment-16262449)
Mon, 21 Apr 2008 14:01:41 +0800
你應該先確認你想讀入的那些文件,其內容都是 utf-8 的。

此外,從程式碼來看,既然你已經完全處理掉了 charset 的編碼動作,那麼你應避免調用 mb_send_mail() ,多一個轉接多一隻鬼。你應該選擇用 PHP mail() and charset encoding question, part 1 的方式送信。
bovaho2000@yahoo.com.tw(我熊) (#comment-17799331)
Fri, 24 Oct 2008 12:24:50 +0800
只要不載入 mbstring extension 或是在 php.ini 中設定 mbstring.func_overload = 6(not overload mail())
-----------------------------
當我在php.ini下查看。
發現這個本來就沒有載入了
(;mbstring extension =0 )
仍然呈現亂碼。
似乎~並不是出自於這裡的問題
未留名 (#comment-17888179)
Thu, 06 Nov 2008 02:36:16 +0800
你有試著用 php -m 列出 PHP 編入的 extension 有哪些嗎?如果你的 php 是將 mbstring 直接編譯在一起的話,就會作用。這時不理會 php.ini 中的設定。