こんにちは、エンジニアの@soyanaです。前回記事CakePHP2 で、phpass でハッシュ化されたパスワードが保存されたユーザーテーブルを扱えるようにするに引き続き、CakePHPのTipsをお送りします。
前提として、
- メールフォームの文字エンコーディングは UTF-8
- メール件名、本文の文字エンコーディングは ISO-2022-JP
という環境とします。
Windows 環境から入力された文字列が、機種依存文字の1つである全角チルダ「〜」や全角ハイフン「−」を含んでいた場合に、上記のエンコーディングされると、届くメールが文字化けしてしまうことがよく起こります。 この問題は、波ダッシュ問題や全角チルダ問題といわれており、ハマリがちな問題の1つです。
CakePHP で実装されたフォームで、入力するユーザが意識せずとも、文字化けが起こらないように行った方法をご紹介します。
WordPress では同様のプラグイン Force Wave Dash が公開されており、これを参考に実装を行いました。
まず、変換は、以下のように行うものとします。
見た目の文字 | 変換前 | 変換後 |
---|---|---|
~ | U+FF5E FULLWIDTH TILD | U+301C |
— | U+2014 EM DASH | U+2015 |
- | U+FF0D FULLWIDTH HYPHEN-MINUS | U+2212 |
¢ | U+FFE0 FULLWIDTH CENT SIGN | U+00A2 |
£ | U+FFE1 FULLWIDTH POUND SIGN | U+00A3 |
¬ | U+FFE2 FULLWIDTH NOT SIGN | U+00AC |
コードで行うことは、以下の2点です
- 文字化けしないように変換する beahvior を実装
- model の before save で beahvior で定義した変換メソッドを呼ぶ
テーブル定義
フォームから入力されたメールを保存するテーブル定義は、以下とします。
CREATE TABLE IF NOT EXISTS emails ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, subject VARCHAR(255) NOT NULL COMMENT 'メール件名', body TEXT NOT NULL COMMENT 'メール本文', created DATETIME DEFAULT NULL COMMENT '作成日時', modified DATETIME DEFAULT NULL COMMENT '編集日時', ) CHARACTER SET 'utf8';
behavior の実装
まずは、behaviror を作成し、問題の文字を対応表にしたがって変換するメソッドを定義します。
<?php // app/Model/Behavior/ForceWavedashBehavior.php /* Thanks to WordPress Plugin Force Wave Dash http://wordpress.org/extend/plugins/force-wave-dash/ */ class ForceWavedashBehavior extends ModelBehavior { public $bad_chars_pat = array( "/\x{ff5e}/u", // U+FF5E FULLWIDTH TILD -> U+301C "/\x{2014}/u", // U+2014 EM DASH -> U+2015 "/\x{ff0d}/u", // U+FF0D FULLWIDTH HYPHEN-MINUS -> U+2212 "/\x{ffe0}/u", // U+FFE0 FULLWIDTH CENT SIGN -> U+00A2 "/\x{ffe1}/u", // U+FFE1 FULLWIDTH POUND SIGN -> U+00A3 "/\x{ffe2}/u", // U+FFE2 FULLWIDTH NOT SIGN -> U+00AC ); public $good_chars = array( "\xe3\x80\x9c", // U+301C WAVE DASH "\xe2\x80\x95", // U+2015 HORIZONTAL BAR "\xe2\x88\x92", // U+2212 MINUS SIGN "\x00\xc2\xa2", // U+00A2 CENT SIGN "\x00\xc2\xa3", // U+00A3 POUND SIGN "\x00\xc2\xac", // U+00AC NOT SIGN ); public function tild2wave (Model $Model, $text) { return preg_replace($this->bad_chars_pat, $this->good_chars, $text); } }
モデルでデータ保存時に自動で文字を変換する
次に、post されたデータが保存時に自動で変換されるように、Email model の beforeSave メソッドを以下のように定義します。
<?php // app/Model/Email.php class Email extends AppModel { public $name = ‘Email'; public $useTable = 'emails'; public $actsAs = array('ForceWavedash’); public function beforeSave($options = array()) { if (!empty($this->data[‘Email']['subject'])) { $this->data['Email']['subject'] = $this->tild2wave($this->data['Email']['subject']); } if (!empty($this->data['Email']['body'])) { $this->data['Email']['body'] = $this->tild2wave($this->data['Email']['body']); } return true; }
これだけで、何も意識せずにメールで文字化けしないように変換されます。 他の機種依存文字などについても同様に定義してやれば、矯正的に文字を変換して保存することができます。