現在、とあるアイドルグループの携帯用アンケートサイトを5営業日以内で作れという至上命令が下っており、そのために久々にCakePHP復活!Ktai Libraryを使ってどのケータイでも対応しちゃうぜ!ちなみにKtai Libraryを使うのは初。本は買ってた。
データベース設計は同僚がやってくれたので(彼はDBのスペシャリスト)、俺はBakeでソースを生成し、デザイナが作ったデザインをViewに組み込み、Modelの設定を行い、Captchaコンポーネントを使った画像認証を組み込み、コントローラーに処理をゴリゴリと書き(Fat Modelになるような仕様ではないため。まぁ汎用的なメソッドはModelに作ったけど)、FireMobileSimulatorで確認しながら開発。
一通り実装が完了したので、実機(俺のAU携帯と後輩のSoftbank携帯)とDoCoMoのシミュレータで試すとやっぱり動かなかったりした。まぁそういうことを試すためだからいいんだけど。ソースを修正しては試す。これによりDoCoMoはOK。SoftbankもOK。しかし、AUだけPOSTしたら404と言われる。なぜだ!
Ktai Libraryを使ってたら、redirectのところでURLの組み立てで変になった箇所があったので(Controller::redirect()の引数に配列形式で値を渡すと壊れる。引数をis_arrayでチェックすると直った)、また似たようなことが起こってるのかなぁ~とApacheのアクセスログを見てみると、ちゃんとPOST先のURLにアクセスしている。しかし、Content-lengthが0。0とはおかしいじゃないか!
まさかと思ってCSRF対策用に使っていたSecurityコンポーネントのBlackHoleCallback関数を設定してログを出すようにしてみたら、ビンゴ。BlackHoleに吸い込まれているじゃないか。しかも、俺はここのPOSTはデータベース更新に関係していないのでCSRF対策してない($this->Security->requireAuthに追加していない)。にもかかわらず、トークンが発行されてるのにも納得がいかない。
何がなんだかわけがわからないので、CakePHPユーザ会で検索してみたら、有力な情報を得た。
Securityコンポーネントのトークンはfieldsetタグ中に囲まれているのだが、このfieldsetタグにはdisplay:none;が設定されている。AU携帯はPOSTするときにdisplay:none;が設定されている領域の値をPOSTしないらしい。サーバ上にはトークンが設定されているにも関わらずトークンがPOSTされないから、トークン不一致でブラックホール行きという仕組みだったのか。
今思いついてる解決策は、
- Formヘルパー自体を修正する(ライブラリ自体の修正はやりたくない)
- $form->create(), $form->end()で取得したソースからfieldsetタグを正規表現で取り除く処理を実装する(若干難しそうだが一番意味がありそう)
- Securityコンポーネントを使わずに独自のCSRF対策を施す(一番現実的か?)
である。まぁ時間があれば2番目で行きたいが、3番目かな。原因が突き詰められたので、Securityコンポーネントを外してAUで試したところ、普通に動いてくれた。あ~、よかったぁ~。ひとまず安堵。
まぁセキュリティ系の課題はあるものの、処理自体は2人日で実装完了。やはりCakePHPの開発効率はかなりいいなぁと思う。簡単かつ早いかつ安心。ただ、時々超ハマる…。
【解決しました!】
次の投稿でこの問題は解決したのでリンクはっておきます。
CakePHP:【解決】AU携帯でSecurityComponent