[PHP]FuelPHPでRequestクラスのレスポンス内容がおかしくなる

Read More



FuelPHPのRequestクラスを使ったリクエストにJSON形式のレスポンスが返ってきたとき、
response()でデータを受け取って展開してみるとBodyがJSON形式の時と配列になる時があった。

この挙動の差がどこで出ているのかしばらくわからなかった、がようやく判明したのでメモ。



--
まず悪さをしていたのはRequestクラスのset_auto_formatメソッド。
こいつがデフォルトでtrueになっているのだが、
何をするかというと自動でレスポンスヘッダーのMIME Typeを解析してデコードしてくれる。
つまりJSON形式でレスポンスを受けたら自動で配列にしてくれる。


このset_auto_format()を常にfalseにしておけば自動変換が起こらないので問題は起きないのだが、
trueのまま使っている場合、または使わざるを得ないような場合は先述したようなJSON形式になったり配列になったりするようなことが起きる。起こる。


なぜそんな挙動になるかというとFuelPHPの中で行われるMIME Typeの判定がうまくいかないから。


順を追って書こう。

header()を使ってContent-Typeを指定しているときchatsetも同時に指定することができる。

こんな感じのやつ。
header("Content-Type: application/json; charset=utf-8");


これこんな書き方もできる。
header("Content-Type: application/json");
文字エンコードを指定してないだけ。

FuelPHPが想定してるのは後者の方らしく、前者のcharsetが入っている形式で書くとうまくMIME Typeの判別をしてくれなくなる。


判別している部分を抜き出してみると以下のように定義されていることがわかる。

■/fuel/core/classes/request/driver.php
protected static $auto_detect_formats = array(
  'application/xml' => 'xml',
  'text/xml' => 'xml',
  'application/json' => 'json',
  'text/json' => 'json',
  'text/csv' => 'csv',
  'application/csv' => 'csv',
  'application/vnd.php.serialized' => 'serialize',
 );
※タブは半角スペースに変換
※CoreのVerは2.0


要はContent-Typeから抜き出したMime Typeがここに定義してあるキーに一致しないからうまくデコードしてくれない結果となるわけだ。
set_auto_format()をTRUEのままちゃんと動かしたいのなら対策の方法は大きくわけて2つある。


ひとつはレスポンスヘッダーのchatsetを書かないこと。
header('Content-Type: application/json');

これはレスポンスの文字エンコードがわからなくなるのでとる方法としてはちょっと微妙。



もう一つはプログラム側の定義を変更する方法。

例えば$auto_detect_formatsにcharset付のものを追加する。
試してないけど以下のような感じ。
protected static $auto_detect_formats = array(
  'application/xml' => 'xml',
  'text/xml' => 'xml',
  'application/json' => 'json',
  'text/json' => 'json',
  'text/csv' => 'csv',
  'application/csv' => 'csv',
  'application/vnd.php.serialized' => 'serialize',
  'application/json; charset=utf-8' => 'json', // 追加する
 );


あるいはMIME Typeを取得する関数あたりに手を入れるとか。

もしかしたらconfig設定で定義に手を加えたりできるのかも知れない。
ちゃんと調べてないからそこまでは知らない。



--
エクセルとかでも自動で電話番号とかの先頭の0を消したりとかそういった余計な機能があるが、
この手の物は全てOFFにしておくに限る。