概要
ファイル選択要素を持つフォームでファイルを取得する手順を整理する。概要は以下のような流れ。
- ファイル選択要素を持ったフォームを含むページを表示する
- ユーザーがファイルを選択して
POST
リクエスト - リクエストを介して、サーバーにアップロード・一時保存されたファイルを取得する
- バリデーションが必要な場合、フォームリクエストを作成して実装
基本例
機能
アップロードファイル取得の機能を、シンプルなコントローラーとビューで確認する。例として、画像ファイルの取得を目的として組み立てていく。
ファイル取得に限って言えば、要点は次の2点。
- ビューでは、ファイル選択要素を持つフォームでファイルを選択、送信
- コントローラーでは、アップロードされたファイルをフォームのリクエストから取得
ルーティング
例として以下のようにルーティングを設定する。
1 2 |
Route::resource('images', 'ImageController') ->only(['index', 'store']); |
設定されるルーティングは以下のとおり。
1 2 3 4 5 6 7 8 9 |
$ php artisan route:list +--------+----------+--------+----------------+--------------------------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+--------+----------------+--------------------------------------------+------------+ ........ | | GET|HEAD | images | images.index | App\Http\Controllers\ImageController@index | web | | | POST | images | images.store | App\Http\Controllers\ImageController@store | web | ........ +--------+----------+--------+----------------+--------------------------------------------+------------+ |
/images
へのGET
リクエストでコントローラーのindex
アクションが呼ばれる- このアクションでフォームページを表示する
- フォームからの
POST
リクエストは/images
に送られ、コントローラーのstore
アクションが呼ばれる- 本来はファイル保存を想定したアクションだが、ここではファイルの内容確認のみ行う
コントローラー~フォーム表示
index
アクションではフォームを含むページを表示するだけ。
1 2 3 4 5 6 7 8 |
class ImageController extends Controller { ........ public function index() { return view('images.index'); } ........ } |
ビュー~フォームとファイル選択要素の設定
表示するページのテンプレートは以下の通りで以下の2点が要点。
FORM
要素でenctype="multipart/form-data"
を指定しているINPUT
要素でtype="file"
としている
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>画像ファイル選択</title> </head> <body> <h1>画像ファイル選択</h1> <form method="post" action="{{ route('images.store') }}" enctype="multipart/form-data"> @csrf <input type="file" name="image"> <input type="submit" value="送信"> </form> </body> </html> |
フォームで選択されたファイルの取得
アップロードされたファイルは、メソッド・インジェクションで得られたRequest
オブジェクトのfile()
メソッドで得られる。file()
メソッドの引数にINPUT
要素のname
属性値を指定することでファイルのオブジェクトを得られる。
以下のアクションでは選択されたファイルの内容をdd()
で表示させ、そこで実行を止めている。
1 2 3 4 5 6 7 8 9 |
class ImageController extends Controller { ........ public function store(Request $request) { $image = $request->file('image'); dd($image); } ........ } |
ローカルのファイルを選択して送信ボタンを押した結果、上記のdd()
で表示された内容を示したのが下記。この例ではJPEGファイルをアップロードしている。
アップロードされたファイルの実体が一時的に保存されるのは/tmp
ディレクトリーで、php.ini
のupload_tmp_dir
で設定されるようだが、コメントアウトされていた。この場合はルート直下の/tmp
になると思われる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
Illuminate\Http\UploadedFile {#1244 ▼ -test: false -originalName: "18420_smile1.jpg" -mimeType: "image/jpeg" -error: 0 #hashName: null path: "/tmp" filename: "phpEyN1ug" basename: "phpEyN1ug" pathname: "/tmp/phpEyN1ug" extension: "" realPath: "/tmp/phpEyN1ug" aTime: 2021-10-17 19:22:08 mTime: 2021-10-17 19:22:08 cTime: 2021-10-17 19:22:08 inode: 67201770 size: 604673 perms: 0100600 owner: 1000 group: 1000 type: "file" writable: true readable: true executable: false file: true dir: false link: false } |
バリデーション
フォームリクエスト
フォーム入力からファイルアップロード時にバリデーションをかける場合、フォームリクエストを使うとコントローラーで行うよりも明快になる。
フォームリクエストはartisanで作成する。
1 2 |
$ php artisan make:request ImageRequest Request created successfully. |
フォームリクエストファイルはapp/Http/Requestsディレクトリーに作成され、このファイルにバリデーションの条件を記述する。条件は配列で書くか、文字列内で'|'
で連結してもよい。
フォームリクエスト生成時にはauthorize()
の戻り値はfalseになっているが、ここでは無条件にtrue
としている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class ImageRequest extends FormRequest { public function authorize() { return true; } public function rules() { return [ 'image' => [ // ファイルがアップロードされている 'file', // ファイル形式がJPEGかPNG 'mimes:jpeg,jpg,png', // 画像のサイズ 'dimensions:min_width=100,min_height=100,max_width=500,max_height=500', ], ]; } } |
ここでは画像ファイルを想定したバリデーションをかけているが、画像以外のファイルを扱う場合は、MIMEタイプをpdf
やdoc
など様々なファイル形式で指定。
また、ファイルサイズをmax:xxx
のようにKB単位で制限することもできる。
なおここではファイルがアップロードされていないときは$image
はnull
となるが、ファイル指定を必須とする場合はrequired
を指定し、エラーメッセージでファイル指定を促すなどの対応をする。
エラー表示
フォームリクエストでのバリデーションの結果エラーがあると、検証結果が$errors
に記録され、もとのビューにリダイレクトされる。
ここでは、以下のようにフォーム入力のテンプレートで@foreach
を使って$errors
の内容を全て表示させている。$errors
の使い方についてはこちらを参照。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<!DOCTYPE html> <html lang="ja" dir="ltr"> <head> <meta charset="utf-8"> <title>画像選択</title> </head> <body> <h1>画像選択</h1> <form method="post" action="{{ route('images.store') }}" enctype="multipart/form-data"> @csrf <input type="file" name="image"> <input type="submit" value="登録"> </form> {{-- バリデーションエラー表示 --}} @foreach ($errors->all() as $error) <p>{{ $error }}</p> @endforeach </body> </html> |