mb_send_mail、mb_encode_mimeheaderの文字化けのまとめ(半角カタカナなど)
出力される文字コード
変換前の文字コード
半角カタカナが????に文字化けする場合
38バイト目(74文字)以降で文字化けする場合
まとめ
[参考記事] メールテキストの1行の文字数制限(最大1,000文字、78文字以下であるべき)
[参考記事] mb_send_mailでCCやBCCを指定する 表示名を指定する
出力される文字コード
mb_send_mail、mb_encode_mimeheaderともに標準の設定ではUTF-8の文字コードでエンコードされます。
Subject: =?UTF-8?B?xxxxxxxxxxxxxxxxxxxxxxx?= From: =?UTF-8?B?xxxxxxxxx==?=<from@example.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: BASE64
件名・本文・メール送信者名はすべてUTF-8をBase64エンコードされて送信されています。
UTF-8で送信すると、受信するメーラーによって文字化けが発生します。
文字化けしないようにするには、ISO-2022-JP(JISコード)にする必要があります。
UTF-8ではなく、ISO-2022-JP(JISコード)で送信するには、mb_languageを設定します。
PHPコードでは
mb_language("Japanese");
または
mb_language("ja");
.htaccessまたはhttpd.confでは
php_value mbstring.language "Japanese"
php.iniでは
mbstring.language = Japanese
mb_languageをJapaneseまたはJaに設定するとmb_send_mail、mb_encode_mimeheaderの挙動が変わり、メールソースは次のようになります。
Subject: =ISO-2022-JP?B?xxxxxxxxxxxxxxxxxxxxxxx?= From: =?ISO-2022-JP?B?xxxxxxxxx==?=<from@example.com> Content-Type: text/plain; charset=ISO-2022-JP Content-Transfer-Encoding: 7bit
mb_languageのマニュアルには次のように書かれています。
mb_language
mb_language ([ string $language = mb_language() ] ) : mixed
現在の言語を設定あるいは取得します。
パラメータ
language
e-mail メッセージのエンコーディングとして使用します。有効な言語は、"Japanese", "ja","English","en", "uni" (UTF-8) です。 mb_send_mail() は、e-mail をエンコードする際にこの設定を使用します。
言語とその設定は、Japanese の場合は ISO-2022-JP/Base64、uni の場合は UTF-8/Base64、English の場合は ISO-8859-1/quoted printable です。
出力される文字コードはmb_languageにより決まり、mb_send_mail、mb_encode_mimeheaderに渡される文字列から自動的にエンコードがされます。
mb_encode_mimeheaderは第2引数に指定した場合、その設定が優先されます。デフォルトはmb_languageで決まる文字コードです。
変換前の文字コード
変換前の文字コードは?というと、『mb_internal_encodingで決まる』というのは間違いです。
マニュアルには次のようにあります。
mb_send_mail
mb_send_mail ( string $to , string $subject , string $message [, mixed $additional_headers = NULL [, string $additional_parameter = NULL ]] ) : bool
email を送信します。ヘッダと本文は mb_language() の設定に基づき変換、エンコードされます。 これは mail() のラッパー関数です。詳細は、 mail() を参照ください。
mb_encode_mimeheader ( string $str [, string $charset = mb_language() によって決まる値 [, string $transfer_encoding = "B" [, string $linefeed = "\r\n" [, int $indent = 0 ]]]] ) : string
MIME ヘッダエンコーディング方式によって文字列 str をエンコードします。
パラメータ
str
エンコードする文字列。 mb_internal_encoding() と同じエンコーディングにしなければいけません。
charset
charset は、str の変換後の文字セット名です。デフォルトは、現在の NLS 設定 (mbstring.language) によって決まります。
transfer_encoding
transfer_encoding は MIME エンコーディングの 方式を指定します。"B" (Base64) または "Q" (Quoted-Printable) のどちらかでなければなりません。 デフォルトは "B" です。
linefeed
linefeed は EOL (行末) のマーカで、 mb_encode_mimeheader() が行を折りたたむ (≫ RFC 用語で、 ある一定より長い行を複数行に分割することを言います。 分割する長さは、現在 74 文字に固定されています) 際に利用します。 デフォルトは "\r\n" (CRLF) です。
indent
最初の行の字下げ (ヘッダで str の前におく文字数)。
マニュアルも間違っています。
『出力される文字コードであればそのまま、出力される文字コードと異なればmb_internal_encodingで決まる』
というのが、正しい挙動のようです。
つまりmb_encode_mimeheaderの第1引数の『mb_internal_encoding() と同じエンコーディングにしなければいけません。』は間違いです。
渡す文字列の文字コードがUTF-8であれば、ISO-2022-JPに変換して渡すか、mb_internal_encodingをUTF-8に設定する。
渡す文字列の文字コードがShift-JISであれば、ISO-2022-JPに変換して渡すか、mb_internal_encodingをSJISに設定する。
ということになります。
PHPコードでは
mb_internal_encoding("UTF-8");
.htaccessまたはhttpd.confでは
php_value mbstring.internal_encoding UTF-8
php.iniでは
mbstring.internal_encoding UTF-8
半角カタカナが????に文字化けする場合
ISO-2022-JP(JISコード)には半角カタカナがありません。
全角文字が文字化けせず半角カタカナのみが文字化けするのは、ISO-2022-JPに変換する箇所で文字化けが発生しています。
PHPの文字エンコードISO-2022-JPで、半角カタカナを扱うにはISO-2022-JP-MSを使用します。
このISO-2022-JP-MSとは、ISO-2022-JPに対しCP932全文字(重複を除くWindows-31Jの文字)が扱えるよう拡張をした文字コードです。
件名・本文・メール送信者名それぞれをmb_send_mail、mb_encode_mimeheaderに渡す前にISO-2022-JP-MSに変換します。
$email_from_name = mb_convert_encoding($email_from_name,"ISO-2022-JP-MS","UTF-8"); $email_body = mb_convert_encoding($email_body,"ISO-2022-JP-MS","UTF-8"); $email_subject = mb_convert_encoding($email_subject,"ISO-2022-JP-MS","UTF-8"); $header="From: " .mb_encode_mimeheader($email_from_name) ."<from@example.com>"; mb_send_mail($email_to,$email_subject,$email_body,$header);
このようにmb_internal_encodingで指定された文字コードではなく、mb_languageで決まる文字コード(JapaneseであればISO-2022-JP)でも正しく動作するため、mb_encode_mimeheaderのマニュアルにある『mb_internal_encoding() と同じエンコーディングにしなければいけません。』は間違いです。
ただし半角カタカナは機種依存文字のため、受け取り側のメーラーが半角カタカナを表示できなければ、そもそも半角カタカナは表示できません。
38バイト目(74文字)以降で文字化けする場合
これはかつてあったPHPのバグです。
RFCで定義されているメールの仕様では、メールテキストの1行の文字数は78文字以下であるべきとあります。
[参考記事] メールテキストの1行の文字数制限(最大1,000文字、78文字以下であるべき)
mb_encode_mimeheaderは、文字数が長いと次のように38バイトごとに分割されてエンコードされます。
=?ISO-2022-JP?B?GyRCIzEjMiMzIzQjNSM2IzcjOCM5IzAjMSMyIzMjNCM1IzYjNyM4GyhC?= =?ISO-2022-JP?B?GyRCIzkjMCMxIzIjMyM0IzUjNiM3IzgjOSMwIzEjMiMzIzQjNSM2GyhC?= =?ISO-2022-JP?B?GyRCIzcjOCM5IzAjMSMyIzMjNCM1IzYjNyM4IzkjMBsoQg==?=
この分割された部分で文字化けが発生していたようです。
(現在、事象を確認できないため未確認)
このため38バイト以下で文字列を分割してmb_encode_mimeheaderでそれぞれを変換するというラッパーが必要だったようです。
まとめ
mb_language("Japanese");
を記述する。
(これにより出力文字コードがISO-2022-JPになります。)
mb_send_mail、mb_encode_mimeheaderに渡す文字列をISO-2022-JP-MSにエンコードする。
mb_convert_encoding($email_from_name,"ISO-2022-JP-MS","UTF-8");
(これにより半角カタカナの文字化けが解消されます。)
ただしmb_encode_mimeheaderのマニュアル通りに仕様変更された場合、この設定では挙動がおかしくなることが考えられます。
mb_language("Japanese"); $email_to = "to@example.com"; $email_from_name = "テスト test テスト"; $email_body = "テスト test テスト"; $email_subject = "テスト test テスト"; $email_from_name = mb_convert_encoding($email_from_name,"ISO-2022-JP-MS","UTF-8"); $email_body = mb_convert_encoding($email_body,"ISO-2022-JP-MS","UTF-8"); $email_subject = mb_convert_encoding($email_subject,"ISO-2022-JP-MS","UTF-8"); $header="From: " .mb_encode_mimeheader($email_from_name) ."<from@example.com>"; mb_send_mail($email_to,$email_subject,$email_body,$header);
関連記事
- 1ファイルにclassを記述して実行する方法
- PHP Startup: Unable to load dynamic libraryのエラーの解決方法
- CakePHP1系(CakePHP1.3)をPHP7・PHP8以降に対応させる方法
- Composerコマンドでウクライナへのメッセージが表示されたことがあります
- Composerをインストールする方法と使い方
- PHPのPEARは2019年に改ざんされたことがあります
- PostgreSQLでSCRAM authentication requires libpq version 10 or aboveと出るとき
- Apacheで所有権や書き込み権限があるにも関わらずPermissions deniedが出る場合
- PCやスマホがネットワーク内にあるかどうかを調べる(在宅かどうかの判断)
- プログラムでもっとも正確に日本の祝日を求める方法(内閣府公表CSVの過去3度の改訂履歴)
- EC-CUBE2系で商品を大量にカートに入れると注文情報が抜けたりカートが消えたりする
- Smarty2をPHP7に対応させる方法(The /e modifier is no longer supported Smarty_Compiler.class.php, line 270)
- CakePHPのバージョンごとのシステム要件
- yumのius(iuscommunity.org)でエラーが出る場合
- iusリポジトリで公開されているパッケージの一覧
- phpMyAdminでログイン画面を出さずにデータベースに接続する方法
- さくらサーバ(さくらのレンタルサーバ)でcronを使ってPHPを定時実行する
- php.ini が見つからない時
- PHPでMySQLなどにPDO接続をすると、could not find driverのエラーが出る場合
- PHP Strict Standards: Non-static method と出る場合の対処法
- Twitter APIでのエラーの一覧
- CakePHPでカラムを比較してSELECTする方法
- ImageMagick更新で『PHP Startup: Unable to load dynamic library '/usr/lib/php/modules/imagick.so'』エラーが出る場合
- コマンドやphpMyAdminで複数のデータベースに接続できるユーザーを作成する方法
- phpMyAdminで『information_schema』などを非表示にする方法
- ディレクトリが存在するにもかかわらず、『No such file or directory』エラーが出る
- PDO_MYSQLをインストールする方法
- PEAR・PECLをインストールする方法
- file_get_contentsで$http_response_headerを使用するときの注意点
- サイトの更新情報をPINGサーバに送信する方法
- インクルードパスを設定する方法
- HEADリクエストを排除してサーバ負荷を軽減させる
- cron実行時の標準出力のメールを飛ばさない方法(cron実行時に毎回メールを飛ばさない)
- cron実行時のPATHなどの環境変数を確認する方法
- cronのメール送信先を指定する方法(cronごとに送信先のメールアドレスを指定する方法)
- cron実行時に『/bin/sh: 〜〜: command not found』と出てcronが実行されない場合
- 『crontab -r』でcronの設定を間違って消してしまった場合の対処法
- 日本語名のフォルダを作成する場合の注意点
- rename()を実行すると『Operation not permitted』とエラーが表示される
- cronを実行すると『TERM environment variable not set.』というエラーメールが飛ぶ
- 「ID」や「ID_xxxx」という文字列があるCSVファイルをExcelで開くとSYLKエラーが出る
- Excelの日付が数字になるときの対処法
- PHPでfacebook投稿時に公開範囲を指定する方法
- PHPで複数の画像をfacebookに投稿する方法
- PHPでfacebookのフィード(ウォール)に投稿する方法
- PHPでのfacebookアプリの認証処理(APIを使うユーザー認証)
- facebook APIを使用する時にfacebook Appsでアプリを登録するまでの流れ
- SELECTタグで色を選択する場合のサンプル
- POSTでアップロードできるファイルサイズの制限を変更する方法
- Zend Optimizerのインストール
- Zend Serverとは
- Live Commerceとは
- SSL(HTTPS)でファイルのダウンロードができない場合
- ファイルダウンロード時のファイル名が文字化けする対処法
- simplexml_load_file()、simplexml_load_string()でparser error : Input is not proper UTF-8, indicate encoding !
- Deprecatedエラーを消す方法 (php.iniや.htaccess)
- Cactiのインストール RRDToolを利用したサーバ監視ツール
- JISコードでstrlenの文字数が合わない(目視の文字数とstrlenの文字数が異なる)
- echoしても文字は表示されないのに、emptyがtrueにならない
- [暗号化]ブロック暗号とは(AES/DES/Blowfish PKCS5Padding ECB/CBC IV)
- == と === の違い(比較演算子)
- Firefox、Chromeなどで文字化けを防ぐ方法 ヘッダー情報に文字コードを指定
- CakePHP、Symfony、Zend Frameworkの比較
- ブラウザの中止ボタンを押した後も処理を実行させる方法 タイムアウト以外の停止
- HTMLファイルのエンコードを『内容から判別する』にしない方法
- SQL Buddy ブラウザベースのMySQL管理ツール
- Twitter APIを使用する (Twitterアプリケーション登録)
- Mantisのインストール
- Mantisのユーザー管理テーブル(mantis_user_table)
- create_functionでメソッドを使用する方法
- strtotimeでmonthを使用するときの注意点
- コマンドラインからpearを実行するとエラーが出る 環境変数PHP_PEAR_PHP_BINの設定
- PEARを更新する方法
- zend_mm_heap corrupted とは
- switch文とif文の違い
- fgetcsv関数を文字化け対応 setlocaleの文字コード指定
- Deprecatedの修正例(POSIX)
- Fatal error: Call to undefined function imagecreatefromjpeg() の対処法
- PHPをyumでインストールする
- php_network_getaddresses: getaddrinfo failed: Temporary failure in name resolutionの対応
- fsockopenでSSLサーバに接続する
- PHPでPDFファイルを作成する FPDF FPDI TCPDF
- 『このインターネットのサイトを開くことができません。』と出て、ファイルをダウンロードできない
- 複雑なExcelファイルをプログラムで作成する方法
- Excelで保存したときのCSVファイルの仕様
- フォーム要素の属性名の『ドット( . )』は『アンダーバー( _ )』に変わります
- サブドメインにアンダーバーがあるとクッキーは使えない
- アンダーバーのあるドメインではセッションクッキーは使用できません
- NetBeans6のインストール(JavaだけでなくRuby、PHP、C/C++に対応した統合開発環境)
- memcachedを使用する(memcacheライブラリ)
- date.timezoneを設定するとPHPが早くなる
- PHPフレームワークの一覧
- mbstringエミュレータ
- Fatal error: Maximum execution time of 30 seconds exceededの対処法
- PHPのインストール
- 例外処理(Exception)
- Windows版PHPにPEAR・PECLをインストールする
- PHPをコマンドラインから使用する方法
- 画像の保存やメール転送を制限する方法
- PHPの閉じタグは書いてはいけない
- $_SERVER['PHP_SELF']は危険?
- Net_UserAgent_Mobile 携帯判別PEARパッケージの使い方と注意点
- stdClassクラスとは
- ユーザーエージェントからのキャリア、世代判別
- クラスとオブジェクト
- str関数、preg関数、ereg関数の速度比較
- 配列値格納の構文と組み込み関数による速度比較
- 正規表現のパターン文字列に日本語文字を使うときの注意
- ダブルクオート/シングルクオート/ヒアドキュメント、echo/printの速度比較
- forとforeachの速度比較
- SJISじゃなくてSJIS-win、EUC-JPじゃなくてeucJP-winを使おう
- 文字列の一部を得る関数mb_substrとmb_strcutの違い
- mb_strlenやmb_strimwidthの注意点
- failed: No space left on device
- VGA端末用に出力画像を拡大縮小する方法
- VGA端末の画像表示対応
- SSL通信かどうか
- docomo端末でCSSを使うには
- yumで、より新しいパッケージをインストールする方法(CentOS)
- 住所や駅名などから緯度経度を取得する
- empty関数について
- $_REQUESTに入る値と、その優先順位
- mail関数やmb_send_mail関数でReturn-Pathを設定する方法
- 携帯サイトのmailtoを端末ごとに書き換える関数
- MySQLのソケットエラー
- EclipseでPHPプロジェクトにする方法
- Softbankの携帯で文字の色を白にするときは注意
- mailtoの使い方
- 携帯サイトでのmailtoの使い方
- mailto本文での改行 ドコモのN、Pで送信に失敗します
- 数字(0〜9)のみかどうかを調べる正しい方法
- PCからデコメールを送るときの仕様
- PHPのバージョン表記の隠蔽
- quoted-printable文字列の変換
- Mantisのメール文字化け
- Issue-Tracker [バグ追跡システム]
- phpBugTracker [バグ追跡システム]
- eGroupWare [バグ追跡システム]
- OpenTask [バグ追跡システム]
- <docomo>タグ、<au>タグ、<softbank>タグの使用例
- 動的ページを静的ページに偽装する方法
- 『サイトが移動しました』を出さない方法
- セッション固定攻撃(session fixation)
- Softbankで絵文字を表示させる
- 位置情報・GPS情報の取得方法
- サイトを公開するときの設定
- クッキー(cookie)について
- セッションの有効期間とか設定とか挙動とかを調べました
- 携帯電話端末の判別ライブラリ Net_UserAgent_Mobile
- 個体識別情報・UIDの取得方法
- OpenPNEのツッコミどころ
- magic_quotes_gpc = On の対策
- Windows版PHPのインストール
- Mantis(マンティス) バグ管理システム
- CakePHP
- Symfony(シンフォニー)
- EC-CUBE
- Zen Cart(ゼン・カート)
- OsCommerce
- OpenPNE
- PukiWiki
- MediaWiki
- Wordpress
- Nucleus
- Movable Type
- NetCommons(ネットコモンズ)
- Joomla(ジュームラ)
- Drupal(ドルーパル)
- XOOPS Cube
- Geeklog(ギークログ)
- UTF-8からSJISで文字化け
- ファイル操作
- Smarty
- 正規表現
- ちいたん
- Symfony
- サンプルコード
- EC-CUBE
- Zend Framework
- Ethna
- OpenPNE
- CakePHP
- WordPress
- XOOPS Cube
- Drupal(ドルーパル)
- FPDF 1.52 リファレンス
- Doctrine
- 講座
- Yii
- Live Commerce
- SOAP拡張モジュール
- PEAR
- Composer
スポンサーリンク