スライド1: モバイル開発@sym fony第35回PHP勉強会@トライコーン亀本 大地(a.k.a: yudoufu)2008/08/31
スライド2: 自己紹介・ ゆどうふ(id:Yudoufu)・ ゆどうふと焼き肉が大好きなぺちぱー・ 実は今日が誕生日・ 焼き肉好きぺちぱーなのにヤサイ(831)の日生まれ・ …これは懇親会。。。き 期待なんてしてないんだからねっ><・ あっ、石を投げないでっ!
スライド3: 今日話すこと・ モバイルサイト開発のポイント・ キャリアごとの違い(3G限定で)・ symfonyでモバイル開発・ symfony(1.0)でどう解決していったか・ 具体的な実装の話
スライド4: モバイルサイト開発・ キャリア/端末の違いを意識した開発が必要・ キャリア/端末情報の取得・ 独自定義のHTTPヘッダー等から取得・ HTML/CSS・ 文字コードのgdgd・ 絵文字・ セッションとCookie・ Cookieが使えない機種/キャリアの存在
スライド5: HTM L/CSSの仕様・ 全キャリアでXHTML/CSSが利用可・ キャリア毎にDTD宣言を変える・ DoCoMo・ HTTPヘッダにapplication/xhtml+xml必須・ iCSS:独自仕様のインラインCSS・ Au・ 外部CSSが利用可能・ 子孫セレクタ等は効かない・ SoftBank・ 外部CSSが利用可能・ 子孫セレクタもOK
スライド6: HTM L/CSSのハマりどころ・ ハマり ①:fontサイズの指定・ サイズの変化がバラバラ・ DoCoMoとSoftBankはsmallと指定したら小さくなるのに、Auは小さくならない。。。とか・ ハマり ②:input要素・ 入力モード制御がカオス・ ハマり ③:mailtoの文字コード・ SoftBankのみUTF8でURLエンコード・ これらは、統一テンプレートで解決するのは無理。・ 何かしらの、切り替える仕組みが必要
スライド7: 文字コードの押さえ所・ DoCoMo・ Shift_JIS or UTF8・ UTF8だと機種によってPOSTの際に文字が消える。・ Au・ Shift_JIS or UTF8(非公式)・ SSL領域はUTF8が使えない・ SoftBank・ Shift_JIS or UTF8・ Shift_JISでは、機種によって絵文字がPOSTされてこない。・ それぞれ、赤字の文字コードで出力するべき。
スライド8: sym fonyでモバイル開発・ ライブラリや拡張をうまくやっておくと、通常のWebサイトと同様の開発が可能・ 自分はどんな対応をしているか?を紹介4. モバイルフィルタキャリア判定の実装絵文字/文字コード変換CSSの切り替えテンプレートとモバイル用ヘルパーセッションのモバイル対応
スライド9: sym fonyのフィルタ
スライド10: モバイルフィルタの作成・ モバイル特有の処理を行うフィルタクラスを作成・ apps/app_name/config/filters.yml に追記rendering: ~web_debug: ~security: ~# generally, you will want to insert your own filters heremobile:class: myMobileFiltercache: ~common: ~flash: ~execution: ~
スライド11: モバイルフィルタの作成・ apps/app_name/lib/myMobileFIlter.class.php<?php class myMobileFilter extends sfFilter { public function execute($filterChain) { // execute()の前に書くとpreFilter $filterChain>execute(); // execute()の後に書くとpostFilter } }・ sfFilterを継承したクラスに実装を加えていく
スライド12: キャリア判別・ Net_UserAgent_Mobileを利用・ symfonyのautoload機構・ app/app_name/config/autoload.yml を作成autoload: PEAR: name: PEAR files: Net_UserAgent_Mobile: /path/to/Net/UserAgent/Mobile.php・ これで、symfonyのautoload対象となるので、これをmyMobileFilter内で利用
スライド13: キャリア判別・ myMobileFilter.class.php (抜粋)public function execute($filterChain) { $request = $this>getContext()>getRequest(); $response = $this>getContext()>getResponse(); if ($this>isFirstCall()) { $agent = @Net_UserAgent_Mobile::singleton(); switch (true) { case $agent>isDoCoMo(): $carrier = 'docomo';出力ヘッダを指定 $response>setContentType('application/xhtml+xml; charset=Shift_JIS'); break; case $agent>isEzweb(): // 中略 } $request>setAttribute('agent', $agent); $request>setAttribute('carrier', $carrier); } $filterChain>execute();preFilter部に設定・ 判別結果をRequestのattributeに入れておく
スライド14: 絵文字の変換・ sfPictogramMobilePlugin を利用・ 手前味噌(^^;ゞ$ symfony plugininstall http://blog.asial.co.jp/data/sfPictogramMobilePlugin0.0.4.tgz・ myMobileFilter.class.php (抜粋) ・ ・ $request>setAttribute('agent', $agent); $request>setAttribute('carrier', $carrier); $pictogram = sfPictogramMobile::factory($carrier, 'utf8'); $request>setAttribute('pictogram', $pictogram); } $filterChain>execute();文書全体を取得 $content = $response>getContent(); $content = $request>getAttribute('pictogram')>replace($content); $response>setContent($content); } }postFilter
スライド15: 文字コードの変換・ 内部の運用文字コードはUTF8に統一する。・ 入出力時に、キャリア毎に表示エンコードとの相互変換を行う。・ DoCoMo : Shift_JIS・ Au : Shift_JIS・ SoftBank : UTF8・ で運用。・ コードは長くなりすぎるのでかいつまんで。。。
スライド16: 文字コードの変換・ 入力時$parameter = $request>getParameterHolder()>getAll();・ preFilterにて入力データ全体を取得し、これに再帰的な文字コード変換を施す。・ 絵文字の変換は$pict_output = sfPictogramMobile::factory($carrier, $pict_encode);$value = $pict_output>convert($value);mb_convert_variables($internal_encoding, $view_encoding, $value);$value = $pictogram>restore($value);・ のようにすると、化けずにエンコードできる。・ 出力時・ 出力する$content全体に文字コード変換
スライド17: CSSの切り替え・ 外部CSSを設定し、キャリア毎に切替・ myMobileFilter.class.php (抜粋)if ($this>isFirstCall()) { $request = $this>getContext()>getRequest(); $agent = @Net_UserAgent_Mobile::singleton(); switch (true) { case $agent>isDoCoMo(): $carrier = 'docomo'; $response>setContentType('application/xhtml+xml; charset=Shift_JIS'); $responce>addStylesheet('/path/to/docomo.css'); break; case $agent>isEzweb(): $carrier = 'ezweb'; $responce>addStylesheet('/path/to/ezweb.css'); // 略 ・ ・ ・ CSSを動的に切り替えるように。キャリア別のCSSを指定
スライド18: CSSの切り替え・ DoCoMoがiCSSでインラインしか使えない。。・ HTML_CSS_Mobile を利用・ やっぱり手前味噌(^^;;ゞ$ pear install HTML_CSS$ svn co http://svn.coderepos.org/share/lang/php/HTML_CSS_Mobile/trunk/ /path/to/lib・ 適当な場所にインストール・ myMobileFilter.class.php (抜粋) $filterChain>execute();出力直前にCSSをインライン展開 $content = $response>getContent(); $content = $request>getAttribute('pictogram')>replace($content); if ($request>getAttribute('carrier') == 'docomo') { $content = HTML_CSS_Mobile::getInstance()>setBaseDir('/path/to/doc_root')>apply($content); } $response>setContent($content);
スライド19: テンプレートとヘルパー2. モバイルフィルタの作成2 キャリア判定の実装2 絵文字/文字コード変換2 CSSの切り替え2 テンプレートとモバイル用ヘルパー2 セッションのモバイル対応
スライド20: sym fonyのテンプレート機能
スライド21: テンプレートの対応・ 全体を規定するレイアウトファイルを変更・ apps/app_name/templates/layout.php(抜粋)<? include_partial('global/dtd'); ?><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"><head>・ パーシャルを使ってXML/DTD宣言を切り替える・ apps/app_name/templates/_dtd.phpを作成<?php switch (sfContext::getInstance()>getRequest()>getAttribute('carrier')): ?><?php case 'docomo': ?><?php echo '<'; ?>?xml version="1.0" encoding="Shift_JIS" ?><!DOCTYPE html PUBLIC "//imode group (ja)//DTD XHTML iXHTML(Locale/Ver.=ja/1.1) 1.0//EN" "ixhtml_4ja_10.dtd"><?php break; ?><?php case 'ezweb': ?><?php echo '<'; ?>?xml version="1.0" encoding="Shift_JIS" ?><!DOCTYPE html PUBLIC "//OPENWAVE//DTD XHTML 1.0//EN" "http://www.openwave.com/DTD/xhtmlbasic.dtd">// 以下略。。。
スライド22: テンプレートの対応・ CSSやDTD宣言の動的な切り替えが行われているので、各モジュールのテンプレートファイルはキャリアをほとんど気にせず編集できる。・ 「完全に気にせず」ではないので注意。・ モバイルのHTMLならではの、バッドノウハウが必要になるところもある。・ その他、キャリア毎に切り替えが必要なものはヘルパーとして実装する。
スライド23: モバイルヘルパーの実装・ mailtoやinput要素の問題などを吸収する・ apps/app_name/lib/helper/MobileHelper.phpを作成function m_mail_to($email, $name = ‘ ’ , $options = array(), $default_value = array()) { $carrier = sfContext::getInstance()>getRequest()>getAttribute('carrier'); if ($carrier == 'docomo' || $carrier == 'ezweb') { foreach ($default_value as $key => $val) { $default_value[$key] = mb_convert_encoding($val, 'SJISwin', 'UTF8'); } } return mail_to($email, $name, $options, $default_value);}内部文字コードがUTF8・ なので、docomoとauをmailtoの文字化けをこれで回避SJISにしている
スライド24: モバイルヘルパーの実装・ input要素も同様に作成function m_input_tag($name, $value = null, $options = array()) { $carrier = sfContext::getInstance()>getRequest()>getAttribute('carrier'); if (isset($options['input_style']) && $input_style = strtolower($options["input_style"])) { unset($options["input_style"]); switch (strtolower($input_style)) { case "kana": $options["mode"] = "hiragana"; if ($carrier != 'docomo') { $options["istyle"] = "1"; $options["format"] = "*M"; } else { $options["style"] .= ";wapinputformat:"*<ja:h>";wapinputformat:*M;"; } break; // 中略 } return input_tag($name, $value, $options);}付与する属性を変え、入力モードを適切に切り替えている
スライド25: セッションのモバイル対応2. モバイルフィルタの作成2 キャリア判定の実装2 絵文字/文字コード変換2 CSSの切り替え2 テンプレートとモバイル用ヘルパー2 セッションのモバイル対応
スライド26: セッションのモバイル対応・ DoCoMo全機種とSoftBankの一部機種でCookieが使用不可・ 特定の場合のみsession.use_trans_sidを使う・ apps/app_name/lib/myMobileSessionStorage.class.php を作成class myMobileSessionStorage extends sfSessionStorage{ public function initialize($context, $parameters = null) { $agent = @Net_UserAgent_Mobile::singleton(); if ($agent>isDoCoMo() || $agent>isSoftBank()) { ini_set('session.use_only_cookies', 0); ini_set('session.use_cookies', 0); ini_set('session.use_trans_sid', 1); } parent::initialize($context, $parameters); }}
スライド27: セッションのモバイル対応・ Redirect()の場合にセッションが途切れてしまう。・ apps/app_name/lib/myMobileSessionStorage.class.php を作成class myMobileFrontController extends sfFrontWebController{ public function redirect($url, $delay = 0 ,$statusCode = 302) { $request = $this>getContext()>getRequest(); if ($agent = $this>getContext()>getRequest()>getAttribute('agent')) { if ($agent>isDoCoMo() || $agent>isSoftBank()) { $url = $this>implementParameter($url, SID); } } parent::redirect($url, $delay, $statusCode); } private function implementParameter($url, $implement) { // 略 }}SID(session_id)を含めてリダイレクトURLを再構成
スライド28: セッションのモバイル対応・ ついでに。。。DoCoMoのguidもここで対応class myMobileFrontController extends sfFrontWebController{ public function redirect($url, $delay = 0 ,$statusCode = 302) { // 略 } public function genUrl($parameters = array(), $absolute = false) { $url = parent::genUrl($parameters, $absolute); if ($agent = $this>getContext()>getRequest()>getAttribute('agent')) { if ($agent>isDoCoMo()) { $url = $this>implementParameter($url, 'guid=ON'); } } return $url; } private function implementParameter($url, $implement) { // 略 }}
スライド29: セッションのモバイル対応・ 拡張したクラスを利用するように、設定変更・ apps/app_name/config/factories.yml// 上略all: controller: class: myMobileFrontController storage: class: myMobileSessionStorage param: session_name: symfony・ これで、セッションIDがDoCoMo/SoftBankの場合にQueryStringにつく
スライド30: まとめ?・ Filterやコンポーネントの拡張を活用すれば、モバイル端末に依存する部分のほとんどを無理なく処理できる。・ うまくまとめれば、plugin化も容易なので、効率化も図れる。・ 絵文字・HTML/CSSのぐだぐだ部分なんかも、ライブラリをうまく活用することでテンプレート作成の労力も大幅に減らせる。
スライド31: おわりに・ トライコーンさん、いつも会場提供ありがとうございます><・ ご清聴ありがとうございました。