CakePHPでモバイルサイト開発 - 1日目 -

さっそくプログラムしていく。

1. prefixを有効にする

prefixを有効にするために [app/config/routes.php] に以下を記述する。
参考 http://phptips.seesaa.net/article/102607319.html
[app/config/routes.php]

Router::connect('/m/:controller/:action', array('prefix' => 'mobile'));

この設定により、/m/にアクセスすると、prefixに指定した接頭語がついたメソッドが実行される。
PCページとモバイルページでURLを変えたいときに使える。
※今回やりたいことには必要ない気もしたが、せっかくなので使ってみた。

2. アクションをつくる

1のprefixが有効ならば、/m/にアクセスすると[prefix_action]メソッドがよみこまれる。[/m/hoge/foo]にアクセスするためのアクションを例に示す。

class HogeController extends AppController {
  public function mobile_foo() {
  }
}

3. ビューをつくる

ビューに関しても[prefix_action]でビューを用意すればOK。
2に対応したビューが欲しいときは、[app/views/hoge/mobile_foo.ctp]を用意しよう!

4. レイアウトをつくる

今回はdocomo向けページをつくります。
XHTML1.0で、文字コードShift_JISにします。
[app/views/layout/mobile_base.ctp]

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html PUBLIC "-//i-mode group (ja)
//DTD XHTML i-XHTML(Locale/Ver.=ja/1.0) 1.0//EN" "i-xhtml_4ja_10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"xml:lang="ja">
<head>
<meta http-equiv="Content-Type"
content="application/xhtml+xml; charset=Shift_JIS" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<title><?php eh($this->pageTitle) ?></title>
</head>
<body>
<?php echo $content_for_layout; ?>
</body>
</html>

あとは必要なときにレイアウトをよべばOK。
controllerで[$this->layout = 'mobile_base']とかすれば大丈夫!

5. 表示をととのえる

これでOKだろうと思い、モバイルのページを用意してアクセスしたところ、styleが反映されていなかった。
どうやら、サーバー側で正しいHTTPヘッダが送られていないらしい。
.htaccessに[AddType application/xhtml+xml .html]を追加すればいいらしいが、今回はheaderメソッドを使った。

class HogeController extends AppController {
  public function beforeFilter() {
    //モバイルからの接続
    if (isset($this->params['prefix'])) {
      header('Content-Type: application/xhtml+xml');
      $this->layout = 'mobile_' . $this->layout;
    }
  }
}

styleは反映されたが、今度は文字化けがおこった。
文字コードはEUC-JPのPC向けページと同じところにつくっているせいか、EUC-JPで出力されているみたいだ。
なんとかShift_JISで表示させるために、ob_start()で出力をバッファに記憶して、ob_get_contents()で取り出した文字列をmb_convert_encodingしてみた。
参考 http://www.ideaxidea.com/archives/2008/04/phpob_start.html
[app/views/layout/mobile_base.ctp]

<?php ob_start() ?>
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html PUBLIC "-//i-mode group (ja)
//DTD XHTML i-XHTML(Locale/Ver.=ja/1.0) 1.0//EN" "i-xhtml_4ja_10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"xml:lang="ja">
<head>
<meta http-equiv="Content-Type"
content="application/xhtml+xml; charset=Shift_JIS" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<title><?php eh($this->pageTitle) ?></title>
</head>
<body>
<?php echo $content_for_layout; ?>
</body>
</html>
<?php
$output = ob_get_contents();
ob_end_clean();
echo mb_convert_encoding($output, "SJIS", "EUC-JP");
?>

これで期待通りの表示を得ることが出来た!
今日やったのはとりあえずここまでです。

6. おまけ

アクセスをdocomoのIPアドレスのみに制限するメソッドを書いた。

function is_docomo() {
  $ips = array(
    '210.153.84.[0-9]+$',
    '210.136.161.[0-9]+$',
    '210.153.85.[0-9]+$',
    '124.146.174.[0-9]+$',
    '124.146.175.[0-9]+$',
    '202.229.176.[0-9]+$',
    '202.229.177.[0-9]+$',
    '202.229.178.[0-9]+$',
    );
  foreach ($ips as $ip) {
    if (preg_match("/^{$ip}/", $_SERVER['REMOTE_ADDR'])) {
      return true;
    }
  }
  return false;
}

今思ったけど、$_SERVER['REMOTE_ADDR']に何回もアクセスするのってどうなんだろうか?
$access_id = $_SERVER['REMOTE_ADDR'];
とかして、変数に入れてforeachしたほうがいいかなー。