[php js]POST時、php ://inputの値が空文字になる

phpに対してjsのfetch apiを使って、jsonを送信しようとした時にはまったのでメモ。どうしたらいいかは状況次第です。

原因

まず、php側のコードは以下。

  $test = file_get_contents('php://input');

jsからjsonを送る時には’Content-Type’:’application/json’を設定するかと思いますが、上記を設定すると、php側は$_POSTで取得することができなくなります。

そしてなぜかphp側では空だったのですが、色々と調べてみると。、。。

https://stackoverflow.com/questions/19146984/file-get-contentsphp-input-always-returns-an-empty-string

こちらのページを発見。要約すると、どうもリダイレクトした時点でphp ://inputの中身は空になってしまうそうです。。

また、$_POSTの値も無くなってしまうそう。。

.htaccessでwww有無やhttpとhttpsを統一していると発生する様子。あとはフレームワークでありがちなindex.phpにアクセスさせてそこから各リソースに飛ばすタイプのやつ。困っている方はリダイレクトしていないか見直してみてください。

詳しい解説

リダイレクトする時にはステータスコードが301か302を使うというのが定石かと思います。しかしこの2つのステータスコード、GET以外のHTTPメソッドもGETにしてしまうことが可能なのです。
そして現在全てGETになってしまうのがデファクトスタンダードな状態。

じゃあなぜ困ってない人が多いの?と思われるでしょうが、PHPを使って複雑なシステムを開発する際にはLaravelやWordPressといったフレームワークを使う方がほとんどではないでしょうか。これらフレームワークではリクエストポイントで独自の変数にリクエスト情報を保持しておき、リクエストに応じた画面で呼び出しているので問題ないのです。

じゃあネイティブPHPで「www有り無し統一」や「index.html有り無し統一」をしながらJSONを扱うにはどうどうば良いのでしょう?

実は2014年ごろに、ステータスコード307と308が提唱されました。これは301や302とほぼ一緒なのですが、唯一違うところは「HTTPメソッドをリダイレクト先にも継承することが義務付けられる」という部分です。

対策

Apacheでの対策は、.htaccessでのRewriteRuleで[R=308]のように明示することです。
ただ気をつけなければならないのが、Apacheでは古いバージョンだと308に対応していないので500エラーが発生してしまうこと。

こちらで確認できたのは、Apache2.2系だと307はOKでしたが308は不可能でした。
2.2系のサポートは2017年に切れているので、クラウドサービスやレンタルサーバでは問題ないでしょうが、開発環境をアップデートしていないと発生する可能性はあります。

申し訳ありませんがNginexは詳しくないので調べてません。