要件さえハマれば concrete5 は非常に便利な CMS ツールだが (※ 万能ではない)、少なくとも現状では、日本国内の携帯電話にオフィシャル対応していない点が惜しい。しかし先日 concrete5.4.0.5.ja で仕上げた案件では、携帯電話用ページを作成しつつ、携帯電話によるトップページへのアクセスを携帯電話用トップページへ転送する機能が必須だったため、少々頭を悩ませることになった。

尚、ここで言う 「携帯電話対応」 とは、「concrete5 で構築された PC 向けサイト中の任意のページまたはディレクトリ以下を携帯端末用サイトとし、携帯端末用サイトを携帯電話に搭載されたブラウザーから文字化けすることなく閲覧させる」 と言うだけなので、「ケータイからダッシュボードにアクセスして、新規ページをビシバシ作成可能?」 とか 「デザイン & レイアウト変更も自由自在?」 等と過度な期待をされないよう、あらかじめご了承いただきたい。

concrete5 (PHP) や DB 側の文字エンコーディングは基本的に UTF-8 なのに対し、携帯電話用には Shift_JIS で表示しなければいけない。個人的には、スマートフォン・ユーザー暦が 4年目に突入したこともあって最近の携帯電話の事情をよく知らず、あまり偉そうなことは言えないが、とりあえずネックになるのは、この文字エンコーディングの部分だと思う。ページ内のエリアに収まっているのが独自に定義したブロックだけであれば、view.php やカスタム・テンプレート内で文字エンコーディングを変更できるが、「記事」 等のデフォルト・ブロックを使うこともあるだろうし、そもそもサイト名や meta タグの keyword、description 等、ブロック云々よりもはるかに手前で日本語文字列が登場する可能性が高い。

当初は登場する日本語文字列を表示する部分でいちいち文字エンコーディングを変換しようとしていたが、すぐに無理があることに気付いて、以下のような方針に切り替えた。

  1. 携帯電話用ページタイプを定義。
  2. "1." 専用の header.php と footer.php を用意 (必要に応じて header_required.php と footer_required.php も)。
  3. "1." 専用 header.php 内で、文字列の出力が始まる前に HTTP ヘッダーの "Content-type" を送出し、PHP 出力のバッファリングを開始。
  4. "1." 専用 footer.php または footer_required.php 内で、バッファーの内容を出力。
  5. "4." の際、出力ハンドラーを用いて文字エンコーディング及び全角 → 半角変換を実施。

この方法は PHP が出力する文字を全てせき止めておいて、最後にまとめてエンコーディング等の変換を行いつつ画面に表示するので、各ブロックを処理している途中の段階では、Shift_JIS だの半角だのと気にする必要がなく、楽だと思う。以下の例では "1." を mobile.php、"2." を m_header.php、m_footer.php、m_header_required.php、m_footer_required.php としてそれぞれ用意し、携帯電話用に文字エンコーディングその他を変換している。サンプル中の定数 MOBILE_CHARSET は携帯電話用に変換する文字エンコーディングとして独自に定義しているが、APP_CHARSET はconcrete5 側でデフォルトで存在する、システム側の文字エンコーディングを表す。

・mobile.php (ページタイプ定義ファイル)
<?php
defined('C5_EXECUTE') or die(_("Access Denied."));
$this->inc('elements/m_header.php');
$a_main = new Area('Main');
$a_main->display($c);
$this->inc('elements/m_footer.php');

・m_header.php
<?php
defined('C5_EXECUTE') or die(_("Access Denied."));
define('MOBILE_CHARSET', 'SJIS'); ← 携帯電話用文字エンコーディングを定義
header('Content-type: text/html; charset=shift_jis'); ← HTTP ヘッダーを送出

/**
 * mobileFilter
 * モバイル表示用フィルター: 全角カタカナ・英数字・スペースを半角に変換後、文字エンコーディングを変換
 */
function mobileFilter($buf) {
	return mb_convert_encoding(mb_convert_kana(mb_convert_kana(mb_convert_kana($buf, 'k'), 'a'), 's'), MOBILE_CHARSET, APP_CHARSET);
}
  :
(snip)
  :
ob_start("mobileFilter"); ← 出力ハンドラーを指定してバッファリング開始
Loader::element('m_header_required');
  :

・m_header_required.php
(任意の処理)
  :

・途中の PHP ファイル
  :
echo '日本語は UTF-8 かつ全角で気にせず記述。' . "\n";
  :

・m_footer.php
(任意の処理)
  :
Loader::element('m_footer_required');

・m_footer_required.php
<?php
ob_end_flush(); ← バッファリング終了
  :

ただし、次のように注意する箇所がある。

  1. HTTP ヘッダー "Content-type" を送出するタイミングによっては、文字列が Shift_JIS に変換できていても、ブラウザーが UTF-8 で表示してしまう。
  2. 問答無用で文字エンコーディングを Shift_JIS に変換してしまうと、concrete5 にログインして携帯電話用ページに PC のブラウザーでアクセスした際に、Shift_JIS に変換されたコンテンツは正しく表示されても、画面上部ツールバーのボタン類が文字化けする。

"1." はエンコーディング変換が正しく行えていれば (=ブラウザーの表示を UTF-8/Shift_JIS で切り替えてみる)、まだ何も文字列が出力されていないごく初期の段階で "Content-type" を送出することで、回避できるはず。上手く行かない場合は、header() 実行のタイミングを見直す。

"2." は、"Content-type" の送出と文字エンコーディング変換の実行を何らかの条件で切り替えられれば、解決する。開発環境と本番環境を区別できる場合は $_SERVER['SERVER_NAME'] 辺りが使えるし、環境が区別できなくても、$_SERVER['HTTP_USER_AGENT'] を見れば、変換の必要の有無をある程度判断できる (User agent の偽装は無視)。

一方文字エンコーディング変換は常時実行し、環境に応じて変換後の文字エンコーディング (上記例では MOBILE_CHARSET) を変える、と言うのもありだと思う。携帯電話からのアクセス時は UTF-8 → Shift_JIS に、PC からのアクセス時は無駄な処理になるものの、UTF-8 → UTF-8 にそれぞれ変換する。

また他のページ同様、PC 用に全て UTF-8 で操作する携帯電話用コンテンツ編集ページを別途用意し、携帯電話用ページには 「特定のブロック表示専用ブロック」 を置くだけで直接編集しないと言う、運用でカバーする方法もある。この場合の携帯電話用ページは、任意のブロックを表示させるだけの存在なので、アクセスして来たのが PC ブラウザーだろうが携帯端末だろうが、全ての文字エンコーディングを変換してまい、ログイン後のツールバー文字化けについては気にしない。

尚、携帯電話用コンテンツの表示ページと編集ページを分ける場合は、編集用ページにアクセス権限を設定して、編集はもちろんのこと、表示できる対象を限定しておいたおいた方がいいと思う。

いずれにせよ、開発中は何らかの方法で変換の有無をコントロールして、UTF-8 と Shift_JIS を使い分けられた方が便利だ。

と、いろいろと書いてはみたものの、これはあくまでも時間が切迫する中で苦し紛れに採った方法が上記と言うだけのことで、もっとスマートなやり方があるかもしれない。「こうすれば一発だぜ」 的な方法をご存知の方は、ぜひご一報ください (そもそもデフォルトで携帯対応していた、等と言う衝撃の事実も大歓迎)。

Comments are closed.