【PHP】PHPMailer で文字化けしたときの対処方法

問題になった現象

PHPMailer を使っているシステムで、下記のような現象が報告されてきたので、対処方法について書いておきます。

  • 髙(はしごだか)、﨑(たちざき)といった文字が、必ず文字化けする。
  • 日本語のファイル名を添付すると、ファイル名が文字化けすることがある。特定の文字が必ず化けるのではなく、特定の文字順のときにだけ化ける。
スポンサーリンク

対策1. キャラセットを UTF-8 に変更

以前はガラケーを考慮して、キャラセットを iso-2022-jp(JIS)で送信していたので、髙(はしごだか)、﨑(たちざき)といった範囲外の文字は化けてしまいます。今回はガラケーを考慮せずとも良い案件であったため、キャラセットを UTF-8 にすることで文字化けしないようにします。

対策2. Localeを明示的に指定

添付ファイル名の文字化けの方の原因は、ファイル名を base64 で変換した際に、"/" が出現する場合に文字化けしていたことがわかりました。PHPMailer#addStringAttach()するときに、内部的に basename() が行われるのですが、Localeを指定していないとうまくファイル名が解析できないようです。

修正前のソース

本当はもっと複雑なソースコードなのですが、ざっくりと下記のように実装されていました。

 
var $mailer = new PHPMailer(TRUE);

// 文字セットとエンコーディングの設定
$mailer->CharSet = 'iso-2022-jp';
$mailer->Encoding = '7bit';

// 宛先  山田 太郎 <yamada@example.com>
$address = $this->input->post('f_address'); // yamada@example.com 
$address_name = $this->input->post('f_address_name'); // 山田 太郎
$enc_address_name = mb_encode_mimeheader($address_name, 'ISO-2022-JP', 'B', "\n");
$mailer->_mailer->addAddress($address, $enc_address_name);

// メール表題
$subject = $this->input->post('f_subject');
$mailer->Subject = mb_encode_mimeheader($subject, 'ISO-2022-JP', 'B', "\n");

// メール本文(WYSWYGエディタで入力したもの)
$body = $this->input->post('f_body');

// ・UTF-8 ⇒ ISO-2022-JP へ変換
$mailer->Body    = mb_convert_encoding($body,             'ISO-2022-JP', 'UTF-8');
$mailer->AltBody = mb_convert_encoding(strip_tags($body), 'ISO-2022-JP', 'UTF-8');

// 添付ファイル名(画面からアップロードされる)
$file_name     = $_FILES['f_file']['name'][0];
$file_type     = $_FILES['f_file']['type'][0];
$file_tmp_name = $_FILES['f_file']['tmp_name'][0];

// ・UTF-8 ⇒ JIS へ変換
$enc_file_name = mb_convert_encoding($file_name, 'JIS', 'UTF-8');
$mime_file_name = mb_encode_mimeheader($enc_file_name, 'JIS');
$mailer->addAttachment($file_tmp_name, $mime_file_name, 'base64', $file_type);

// 添付ファイル(データベース等から取得したものを添付するパターン)
$file_name_from_db = $rs['file_name'];
$file_content_from_db = $rs['file_content'];

// ・UTF-8 ⇒ JIS へ変換
$enc_file_name_from_db = mb_convert_encoding($file_name_from_db, 'JIS', 'UTF-8');
$mime_file_name_from_db = mb_encode_mimeheader($enc_file_name_from_db, 'JIS');
$mailer->addStringAttachment($file_content_from_db, $mime_file_name_from_db);

$mailer->send();

修正後のソース

ポイントは下記の通り。

  • CharSetを UTF-8 に設定
  • Endcoding を base64 に設定
  • CharSetを UTF-8 に設定したので、mb_convert_encoding は一切不要
  • CharSetを UTF-8 に設定したので、mb_encode_mimeheader では UTF-8 を指定
  • CharSetを UTF-8 に設定したので、Locale は ja_JP.UTF-8 を指定
  • PHPMailerのaddAttach()の第2引数で渡すファイル名は、PHPMailer自身が適切に mimeheader をつけてくれるので、そのままのファイル名を渡す
 
var $mailer = new PHPMailer(TRUE);

$this->_mailer->CharSet = 'UTF-8';
$this->_mailer->Encoding = 'base64';


// 宛先  山田 太郎 <yamada@example.com>
$address = $this->input->post('f_address'); // yamada@example.com 
$address_name = $this->input->post('f_address_name'); // 山田 太郎
$enc_address_name = mb_encode_mimeheader($address_name, 'UTF-8', 'B', "\n");
$mailer->_mailer->addAddress($address, $enc_address_name);

// メール表題
$subject = $this->input->post('f_subject');
$mailer->Subject = mb_encode_mimeheader($subject, 'UTF-8', 'B', "\n");

// メール本文(WYSWYGエディタで入力したもの)
$body = $this->input->post('f_body');

// もともと UTF-8 なのでそのままセット
$mailer->Body    = $body;
$mailer->AltBody = strip_tags($body);

// 添付ファイル(画面からアップロードされたものを添付するパターン)
$file_name     = $_FILES['f_file']['name'][0];
$file_type     = $_FILES['f_file']['type'][0];
$file_tmp_name = $_FILES['f_file']['tmp_name'][0];

// ・UTF-8 ⇒ JIS へ変換
$mime_file_name = mb_encode_mimeheader($file_name,, 'UTF-8', 'B', "\n");
$mailer->addAttachment($file_tmp_name, $mime_file_name, 'base64', $file_type);



// 添付ファイル(データベース等から取得したものを添付するパターン)
$file_name_from_db = $rs['file_name'];
$file_content_from_db = $rs['file_content'];
// PHPMailer#addStringAttach() で basename() を使用しているため、
// base64変換時に / が出現するとファイル名をうまく判定できないことがある。
// そのため、事前に Locale を設定しておく必要がある。
setlocale(LC_ALL, 'ja_JP.UTF-8');
$mailer->addStringAttachment($file_content_from_db, $file_name_from_db);

$mailer->send();
スポンサーリンク
おすすめの記事