鶏口牛後な日々

心の赴くまま、やりたいことを仕事に。

PHP LaravelとHTMLのinput type="file"タグで複数のファイルを同時にアップロードしたい

私の場合は、画像を最大4枚同時にアップロードし、ストレージに保存するという操作を行いたいと思ったときに課題にぶつかりました。

まず、input type="file"タグは、一つのタグにつき1つしかアップロードできないのが基本です。 multiple="multiple" というのがあって、この属性をつけると複数アップロードできるようになったらしい。(HTML5から)

ただ、これをしたところで、受け取り側のLaravelのコントローラーで、複数のアップロードが確認できず、 最後の1枚しか保存してくれないという事態に行き当たりました。 つまり、読み込みは何度でもできるが、一度読み込んだものをどこかarrayなどに保存しておいてくれるわけではなく、 次のものを読み込むと、先に読み込んでおいたものは上書きされてしまうようでした。 (これの挙動については、multiple属性の仕様を詳しく調べたわけではないので、知りたい方はベット調べてください。)

javascriptで、fileをlistとして保管しておき、submitボタンを押したときに、ajax経由で保存するという方法もあるようでしたが、 ajaxをあまり使ったことがない初心者の私としては、少しハードルが高いと感じました。

結局、以下のやり方がjavascriptをほとんど書く必要もなく、一番簡単にできると思ったので紹介します。

inputタグを最大の読み込み数と同じ数用意します。

<input type="file" id="photo1" name="photo[]" accept="image/*" multiple="multiple">
<input type="file" id="photo2" name="photo[]" accept="image/*" multiple="multiple">
<input type="file" id="photo3" name="photo[]" accept="image/*" multiple="multiple">
<input type="file" id="photo4" name="photo[]" accept="image/*" multiple="multiple">

idはそれぞれを区別できるように別でつけておくようにしてください。 nameは、 name="photo[]" とすることで、4つのインプットタグで受け取った内容を一つの配列としてリクエストに入れてくれます。 classだけにしておいて、jsなどで動きをカスタマイズしている場合、jsがinputタグを一つだと勘違いして、うまく動作してくれない可能性があります。

これで、Laravel側では、 $request->file('photo') として配列を取得してくれます!

ちなみに、inputタグを四つもおいておくのがダサいからどうにかしたい場合は、簡単なjQueryを書いて、 最初一つ目のみを display="block" 他を display="none" にしておいて、順に表示するinputタグを切り替えれば、ユーザーからは毎回同じボタンを押しているような形に見せることができます。

以上。

参考:

PHP: Uploading multiple files - Manual