Smartyでページ出力時に文字コードを変換する
Smartyには、テンプレートがコンパイルされた後や表示の直前に、任意の関数を実行させる拡張機能があります。文字コードがSJIS以外のデータをCSVファイルでダウンロードしたい場合やサーバー上の制限や管理上の制約などでプログラムの文字コードを変更できない場合などに、Smartyの機能で出力時の文字コードを変換することができます。また、携帯向けサイトではヘッダのContent-Typeに「application/xhtml+xml」が指定されていると、PHPの出力バッファの文字コードを出力文字コードに変換する関数mb_output_handlerが使用できません(mb_output_handlerの仕様で「Content-Type: text/*」の場合しか変換ができないためです)。
このようなXHTMLを利用した携帯向けサイト作成の際には、Smartyの機能を利用して出力文字コードを変換します。本項では、テンプレートをdisplayメソッドやfetchメソッドを経由して呼び出し、表示の際に実行されるアウトプットフィルタという機能を利用して文字コードを変換する機能について説明します。
アウトプットフィルタはSmartyのregister_outputfilterメソッドを使って登録します。アウトプットフィルタは以下のように定義し、Smartyインスタンスに登録します。
// アウトプットフィルタの定義
function 関数名($tpl_output, &$smarty)
{
# 処理
return # 処理結果
}
// アウトプットフィルタを登録
$smarty->register_outputfilter(関数名);
上記コードの「$tpl_output」は処理を行うテンプレート出力オブジェクトになります。「$smarty」はSmartyインスタンスになります。アウトプットフィルタを利用して、前ページのサンプルを元に出力文字コードをSJISにする処理を加えます。
// アウトプットフィルタの定義
function filter2sjis($buff, &$smarty) {
return mb_convert_encoding($buff,"SJIS","UTF-8");
}
// アウトプットフィルタを登録
$smarty->register_outputfilter("filter2sjis");
// テンプレートを表示
$smarty->display("books_sjis.tpl");
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html lang="ja"> <head> <title>books</title> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">

文字コードがSJISで表示されていることが分かります。
SmartyでCSVファイルをダウンロードする
管理画面の機能でよく実装されているデータのCSV形式でのダウンロード機能を、Smartyを使って実装します。文字コードをSJISにする機能は前項で作成しておりますので、この機能はそのまま使います。CSVで出力する場合は画面表示を伴わないため、displayメソッドではなくfetchメソッドを使ってテンプレート内容をそのまま出力します。ブラウザでそのまま表示するのではなく、テキストファイルとしてダウンロードさせたい場合にはHTTPヘッダの「Content-Type」を以下のように指定します。
header("Content-type: text/octet-stream");
「octet-stream」はMIMEのサブタイプの1つで「application/octet-stream」とすれば特にファイルの種類を意識することなくバイナリ値の転送として扱われます。サンプルではテキスト形式の1つとしてcsvファイルを出力しているため「text/octet-stream」としています。
また、今回のサンプルはHTML以外のファイルにブラウザからアクセスしますのでHTTPヘッダ「Content-disposition」も指定しています。
header("Content-Disposition: 「inline or attachment」 ; filename=[ファイル名]");
「Content-Disposition」で指定する「inline」「attachement」の属性の意味は以下の通りです。
| メソッド名 | 概要 |
| Content-Disposition: inline | 表示する際に同時に内容も即座に表示する |
| Content-Disposition: attachment | ユーザーに何かのアクションを起こさせてから内容を表示する |
Zipファイルや画像ファイルのダウンロードの際などは「attachment」を指定します。サンプルでは「Content-type: text/octet-stream」でダウンロードさせるファイルとしてHTTPヘッダを指定するので「Content-Disposition」では「inline」を指定しています。
# 略
// アウトプットフィルタを登録
$smarty->register_outputfilter("filter2sjis");
// ファイル名の決定
$file_name = date('Ymd_His') . ".csv";
// ファイル名ヘッダ出力
header("Content-Disposition: inline ; filename={$file_name}" );
// MIMEタイプヘッダ出力
header("Content-type: text/octet-stream");
// HTMLを取得
$csv = $smarty->fetch('books_csv.tpl');
// サイズヘッダ出力
header("Content-Length: ". strlen($csv));
// csvデータ出力
echo $csv;
書籍名,発行日
{foreach from=$books key=k item=i}
{$i.title},{$i.published}
{/foreach}
HTTPヘッダ「Content-Disposition」内のファイル名は「年月日時刻」とし、アクセスされた時刻ごとに変わるようにしています。

上記のようにテンプレートと出力パターンを変更することで、Smartyを使ってCSVでのダウンロード機能を実装できます。
