SSLモバイル

第14回 Smartyでケータイサイトを作ってみる (その1)

yossy先生昨年末にSmarty講座の連載を再開しましたが、今回で最終回になります。
というわけで今回は、今まで説明したプラグインやフィルタなどを用いてケータイ向けのサイトを作ってみたいと思います。

とはいえ、ケータイサイトを作るには色々なノウハウが必要で、その特集をやっただけで1冊の本が書けるぐらい、非常に多岐にわたった知識の説明が必要になります。

なので今回はケータイサイトの細かいノウハウについては必要最低限触れるだけにして、Smartyを使ってケータイサイトを効率よく作るための方法に絞って説明したいと思います。(一応、この連載のメインテーマは「Smarty」ですので……)

なお、今回ケータイサイトの実装方法について、ソフトバンククリエイティブの「PHP×携帯サイト デベロッパーズバイブル」を参考にさせていただきました。

処理の流れ

今回はケータイで閲覧、書き込みが出来る掲示板を作成してみたいと思います。
作成するにあたり、条件を用意したいと思います。

  • キャリアごとにSmartyテンプレートを極力分けない
  • プラグイン関数を作成する
  • フィルタを作成する

ケータイサイトを作るに当たり、一番の障害になるのは 「キャリアの違いをどう吸収するか」 です。
キャリアごとテンプレートを分けるのも一つの方法ですが、今回はテンプレートを共通化し、フィルタや関数などを駆使することでデザイナーの付加を極力少なくすることを目標とします。

前準備

今回の実装ではディレクトリ構成を以下のようにします。

./
|-- cache
|-- configs
|-- htdocs          ドキュメントルート
|-- libs            クラス定義などのphpファイルを格納
|-- plugins         作成したプラグインファイルを格納
|-- templates       テンプレートを格納
`-- templates_c

htdocsがドキュメントルートになります。ApacheなどWebサーバーの設定でここを参照するよう設定してください。 またその際、それ以外のディレクトリが外部から見えないよう注意してください。 そしていつものようにキャッシュディレクトリ(cache, templates_c)はWebサーバーが書き込みできるよう、オーナーやパーミッションを設定してください。

キャリア判定

yossy先生さて最初の課題。クライアントのキャリアを判別するにはどうしたらいいでしょう?

手段の一つとして、クライアントがリクエスト時に送信するUser-Agentの値を解析して判別する方法があります。 もちろん解析ロジックを一から実装してもいいのですが、今回はなるべく簡単にすませようと思います(Smartyがメインの連載ですので)。 PEARにNet_UserAgent_Mobileというパッケージがあるので、今回はこれを使いたいと思います。

インストールにはpearコマンドを使います。なお、このパッケージはまだβ版のため、末尾に-betaを付与するのを忘れないでくださいね。

pear install Net_UserAgent_Mobile-beta

このパッケージにはUser-Agentの値を元にアクセスしてきたクライアントのキャリアを判別するメソッドが用意されていますので、キャリアによってロジックを分ける判定にはこれを用いたいと思います。(*1)

アウトプットフィルタでDOCTYPE切り替えと文字コード変換

まずキャリアに応じてDOCTYPEの切り替えを行います。先ほど説明したNet_UserAgent_Mobileパッケージを利用してキャリアを判別し、それに応じたDOCTYPEを決定します(*2)。今回、XHTMLを出力することを前提として作成しますのでXML宣言を出力し、そのあとDOCTYPEを出力、そしてその後に実際のXHTMLデータを出力します。

この処理をアウトプットフィルタで実現します。アウトプットフィルタは第9回で説明したように、Smartyテンプレートが解析された後に実行されるフィルタです。これをプラグインとして実装します。

plugins/outputfilter.xmldoctype.php

  1  <?php
  2  
require_once('Net/UserAgent/Mobile.php');
  3  
  4  
/*
  5   * Smarty plugin
  6   * -------------------------------------------------------------
  7   * File:     outputfilter.xmldoctype.php
  8   * Type:     outputfilter
  9   * Name:     xmldoctype
 10   * Purpose:  ページ先頭のXML宣言、DOCTYPE宣言をキャリアにあわせて出力する
 11   * -------------------------------------------------------------
 12   */
 13  
function smarty_outputfilter_xmldoctype($output, &$smarty)
 14  {
 15      
// 現在のキャリアを取得
 16      
$agent Net_UserAgent_Mobile::singleton();
 17      if(
$agent->isDoCoMo()){
 18          
$doctype '<!DOCTYPE html PUBLIC "-//i-mode group (ja)//DTD XHTML  i-XHTML(Locale/Ver.=ja/2.3) 1.0//EN" "i-xhtml_4ja_10.dtd">';
 19      }
 20      elseif(
$agent->isEZweb()){
 21          
$doctype '<!DOCTYPE html PUBLIC "-//OPENWAVE//DTD XHTML 1.0//EN"  "http://www.openwave.com/DTD/xhtml-basic.dtd">';
 22      }
 23      elseif(
$agent->isSoftBank()){
 24          
$doctype '<!DOCTYPE html PUBLIC "-//JPHONE//DTD XHTML Basic 1.0  Plus//EN" "xhtml-basic10-plus.dtd">';
 25      }
 26      else{
 27          
$doctype '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0  Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
 28      }
 29  
 30      return 
'<?xml version="1.0" encoding="Shift_JIS" ?>' "\n"  $doctype "\n" $output;
 31  }
 32  
?>

続いて文字コード変換です。今回、出力する文字コードはShift_JISとします。この文字コード変換もアウトプットフィルタを用いて一気に行います。

plugins/outputfilter.shiftjis.php

  1  <?php
  2  
/*
  3   * Smarty plugin
  4   * -------------------------------------------------------------
  5   * File:     outputfilter.shiftjis.php
  6   * Type:     outputfilter
  7   * Name:     shiftjis
  8   * Purpose:  出力をShift_JISに変換する
  9   * -------------------------------------------------------------
 10   */
 11  
function smarty_outputfilter_shiftjis($output, &$smarty)
 12  {
 13      return 
mb_convert_encoding($output'SJIS-win''UTF-8');
 14  }
 15  
?>

これらのフィルタをSmartyインスタンスへ設定します。
第9回で説明したregister_outputfilter()を利用してもいいのですが、プラグインのフィルタを複数指定する場合はSmartyのインスタンス変数autoload_filtersを用いると非常に楽に設定できます。

$smarty->autoload_filters = array('output' => array('xmldoctype', 'shiftjis'));

この例ではアウトプットフィルタにxmldoctype, shiftjisの2種類のフィルタプラグインを設定しています。

例えば以下のようなテンプレートがあったとします。

<html>
<
head>
<
meta http-equiv="Content-Type" content="application/xhtml+xml;  charset=Shift_JIS" />
<
title>てすと</title>
</
head>
<
body>
今日はいい天気ですね。
</body>
</
html>

このテンプレートを表示するPHPにドコモのケータイからアクセスされると以下のように変換され、文字コードもShift_JISに変換されて出力されます。

<?xml version="1.0" encoding="Shift_JIS" ?> <!DOCTYPE html PUBLIC "-//i-mode group (ja)//DTD XHTML  i-XHTML(Locale/Ver.=ja/2.3) 1.0//EN" "i-xhtml_4ja_10.dtd">
<
html>
<
head>
<
meta http-equiv="Content-Type" content="application/xhtml+xml;  charset=Shift_JIS" />
<
title>てすと</title>
</
head>
<
body>
今日はいい天気ですね。
</body>
</
html>

-----
(*1)あくまでUser-Agentだけから判定しているので、この値が偽装された場合はケータイからのアクセスでなくてもケータイであると判断してしまいます。セキュリティ対策などで厳密に判定する必要がある場合は、IPアドレスなども併せて判定する必要があります。

(*2)本当はキャリアだけでなく機種に応じて対応したDOCTYPEにすべきですが、今回は単純化するため、キャリアによる判別のみとします。

「yossy先生のSmarty講座」のトップへ