PHP
laravel

Laravelでmultipart/form-dataのPUT,PATCH,DELETEのパラメタが取れない

問題

RESTFulなAPIサーバを作るとき、パラメタのあるPUTやPATCHメソッドを定義することがよくあります。しかしLaravelで普通に実装すると、パラメタをapplication/x-www-form-urlencodedで渡したときはうまく動きますが、multipart/form-dataだとパラメタが取れません。これはかなり以前からある問題(Input from PUT requests sent as multipart/form-data is unavailable #13457)でこのissueはcloseされているのですが問題は解決していません。(なぜ問題が残っているのにcloseされたのかはよくわかりません)

これはPHPがPOSTメソッド以外ではapplication/x-www-form-urlencodedやmultipart/form-dataで渡されたパラメタの処理をしてくれない仕様だからで、application/x-www-form-urlencodedについてはSynfonyのSymfony\Component\HttpFoundation\Requestクラスがなんとかしてくれますが、multipart/form-dataについては誰も何もしてくれないからです。

対処方法

いくつかの対処方法を紹介します

apiを呼ぶ側で_methodパラメタに本来呼びたいメソッドを設定してPOSTする。

proxyがPUT,PATCHに対応してないときなんかに使う代替手段を利用するやり方です。サーバ側は何もしなくていいですが、使う側には負担になります。

multipart/form-dataを解釈するプログラムを用意する

先ほどのissueの議論の中でもこの方向でプログラムを書いた人がいて、https://gist.github.com/devmycloud/df28012101fbc55d8de1737762b70348 が紹介されています。

ただしいったんphp://inputの内容を変数に受ける実装なので、大きなファイルを扱うAPIなどではこのままでは使えないと思います。

pecl/apfdを使う

apfdはPHPがPOST以外のメソッドでもパラメタの処理をするようになる機能拡張です。PHP本体がデフォルトでこちらの動作になっててもいいと思うのですが、やはり過去との互換性とかいろいろ事情があるのでしょうか。

まとめ

もしextensionの追加ができるならapfdを使うのが一番楽だと思います。