cakeはUTF8で、入出力だけSJIS変換

モバイルとか、既存のSJISで作られたシステムの移行とかで、どうしてもhtml側はSJISにしたいけど、cake使うからこの際システムやDBはUTF8ベースにしたい、そんな感じのことをやる場合。

入力(POSTなど)でphp側で文字コード変換をしてない場合を前提としています。環境はcakePHP1.2RC2です。

Viewファイル、レイアウトファイル、エレメントファイルは全てUTF-8Nで保存しておきます。UTF-8Nですよ、UTF-8で保存してると、?などが先頭に表示されちゃいますから。これで10分ぐらいはまったのですorz


Viewファイルのhtmlは、文字コードはUTF-8Nですが、html側のcharsetはSJISにしておきます。

<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">


やるべきことは、コントローラの中でPOSTデータをSJISからUTF-8にすることと、html出力を全てSJISからUTF-8にすることです。とりあえずコントローラファイルの最初に下記のようなメソッドを用意しておきます。
app/controllers/hoge_controller.php

<?php
class HogeController extends AppController {

//出力文字コード変更(UTF8からSJIS)
function afterFilter(){

	$this->convert_output_encode();
}

//入力文字コード変更(SHIS-winからUTF8)
function beforeFilter(){

	$this->convert_input_encode();

}

上記のコントローラでは、出力するHTMLの文字コードを変更するためにafterFilterでアクションの実行後にapp_controller.phpにこれから記載するconvert_output_encode()メソッドを呼んでいます。(afterFilterで呼ばないと、全ての出力結果を文字コード変換できないため)
入力(POST)されたデータは、アクションを実行する前に、app_controller.phpにこれから記載するconvert_output_encode()メソッドを呼んでいます。


では、最後にapp_controller.phpを下記の場所に作ります。
app/app_controller.php

output = mb_convert_encoding($this->output,'Shift_JIS','UTF-8');

	}

	//POSTされたデータをSJISからUTF8へ変換
	function convert_input_encode(){
		if( !empty($this->data) ){
                       mb_convert_variables('UTF-8', 'SJIS-win',$this->data);
			array_walk_recursive($this->data, array('AppController', 'convert_input_encoding') );
			
		}

	}

	function convert_input_encoding( &$item, $key ){

		$item = mb_convert_encoding( $item, 'UTF-8', 'SJIS-win' );

	}

}
?>

まず、convert_output_encodeでは、すべてレンダリングされた結果のhtmlが$this->outputに入っているので、$this->outputに対してmb_convert_encodingして文字コード変換しています。変換結果を$this->outputに入れてやれば、それがHTMLとして出力されます。

次にconvert_input_encodeでは、POSTデータがあるかチェックし、データがあれば$this->dataを再帰的に文字コード変換していきます。実際の文字コード変換はその下のconvert_input_encodingメソッドを呼んでいます。convert_input_encodingでは、再帰的に配列をたどって渡されたデータを文字コード変換しています。


こんな感じで、お手軽に変換してもらえます。いやぁ便利!


追記
mb_convert_variablesなんていう便利な機能があったんですね。これで配列ごと文字コード変換ができて良い感じ。(ただし配列のキーは変換されないので英語にしたほうが良いです)