#前に社内wikiに書いておいたのを公開してみるテスト。
追記: この情報は若干古いです。ここを読んだ後にこちら読むと良いです。
Catalystでマルチバイトを扱う機会があるのは主に- ユーザーがフォームで入力する値 ($c->req->param())
- データベースからの入出力 (DBIx::Class)
- それ以外の文字列の評価
- View::TTによる出力の生成
- FillInFormによるフォームの埋め込み
- HTTPレスポンス
- 文字コードはUTF8に統一
- データベースにはmysqlを使用
下準備
テンプレート、perlのコードは全てUTF8で書きます。mysqlの文字コードの指定は/etc/my.cnfに
[mysqld] default-character-set = utf8 skip-character-set-client-handshake [mysql] default-character-set = utf8 [mysqldump] default-character-set = utf8
を書いてから起動して、create databaseします。
ユーザーがフォームで入力する値 ($c->req->param())
Catalyst::Plugin::Unicodeを使う。 prepare_parameters時に$c->req->paramsの値にutf8フラグを立ててfinalize時に$c->res->bodyからutf8フラグを落としてくれる。ただしfinalizeメソッドをオーバーライドしているのでFillInFormなどを使う場合には
use Catalyst qw/ ... FillInForm ... Unicode /;
とかして最後にロードするようにする。
(via http://unknownplace.org/memo/2006/03/09#e004)
データベースからの入出力 (DBIx::Class)
DBIx::Class::UTF8Columnsを使う。 $row->get_column/get_columnsでutf8フラグを立てて返す。__PACKAGE__->load_components(qw/UTF8Columns Core/); __PACKAGE__->utf8_columns(qw/name description/);
とかするとutf8_columnsで指定した$row->nameや$row->descriptionにutf8フラグが立つ。
指定していないものにはutf8フラグは立っていないのでマルチバイトコードを扱いそうなカラムは全部指定した方が良いかも。
それ以外の文字列の評価
常にutf8フラグを立てて評価する。utf8::decode($str);
View::TTによる出力の生成
Catalyst::View::TT::ForceUTF8を使う。 テンプレートをutf8フラグを立てて処理する。script/create.pl view TT TT::ForceUTF8
でViewクラスを作るか
すでにあるMyApp::View::TTを
use base 'Catalyst::View::TT::ForceUTF8';
として継承関係を変ればOK。
FillInFormによるフォームの埋め込み
通常は上記のことだけでOKなのですが、まれに
$c->req->param->{name} = 'ほげ';
というような処理をする場合、当然この文字列にはutf8フラグが立っていないのにView::TT::ForceUTF8でレンダリングされたutf8フラグ付きの文字列にfillformしようとするため文字化けします。
対処方法としては、"・それ以外の文字列の評価"で説明したとおり、常にutf8フラグを立てて取り扱えばいいのですが、面倒なときもあるのでHTML::FillInForm::ForceUTF8を使ったCatalyst::Plugin::FillInForm::ForceUTF8ってのを作りました。これだとfillform時に全てutf8フラグを立てるので文字化けは起こらなくなります。
ついでにFV::Sとか使ってると勝手にfillinするおせっかいな処理を抑制するオプション付き。
MyApp->config->(
fillinform->{
auto => 0
}
);
HTTPレスポンス
HTTPレスポンスのcontent-typeはCatalystではデフォルトでutf8が設定されるけど、明示的に指定したい場合はMyApp::Controller::Rootで
sub render : ActionClass('RenderView'){}
sub end : Private{
my ($self, $c) = @_;
$c->forward('render');
$c->res->content_type("text/html; charset=utf8");
}
とかしておけばOK。

コメントする