Laravelでファイルをアップロードする方法を詳細解説
Laravel11.x, Laravel10.x, Laravel9.x, Laravel8.x, Laravel7.x, Laravel6.x, Laravel5.8, Laravel5.7で動作確認を行っています。ファイルのアップロード機能はLaravelのコア機能でバージョンによって手順が変わることはありません。バージョン毎に変わる手順ではないので、一度処理方法を理解することができれば長期にわたって使える知識になります。
本文書ではLaravel11.x, Laravel10.x, Laravel9.x, Laravel8.x, Laravel7.x, Laravel6.x, Laravel5.xを使ってファイルをアップロードする方法を中心に詳細を説明を行っていますがファイルのアップロード機能を使ったアプリケーションを開発する際の参考にできるようにアップロードだけではなく、アップロードしたファイルのブラウザからの閲覧方法についても説明を行なっています。
各バージョンのLaravelがインストール済みの状態で動作確認を行なっていきます。
目次
アップロードフォームの作成
ブラウザ上からファイルをアップロードするためにはフォームの作成を行う必要があります。
ファイルのアップロードフォームをブラウザに表示させるまで以下の設定を行います。
- web.phpへのルーティングの追加
- コントローラーの作成
- 入力フォームのBladeファイルの作成
フォームを表示、ファイルをアップロードするためのルーティングをweb.phpに追加します。
Route::resource('/upload', 'UploadController');
Laravel8以降は以下のようにルーティングの追加を行ってください。
//略
use App\Http\Controllers\UploadController;
//略
Route::resource('upload',UploadController::class);
web.phpで指定したコントローラーUploadControllerをphp artisanコマンドを利用して作成します。
$ php artisan make:controller UploadController
INFO Controller [app/Http/Controllers/UploadController.php] created successfully.
作成されるUploadController.phpにはメソッドが含まれていないのでindexメソッドを追加します。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UploadController extends Controller
{
public function index(){
return view('index');
}
}
ビューファイルの作成を行います。resource/viewsディレクトリの下にindex.blade.phpファイルを作成し、ファイルをアップロードするためのフォームを作成します。formタグのmethod属性にPOST、action属性にはPOSTリクエストの送信先である/uploadを指定します。
ファイルのアップロードを行う場合は、enctype=”multipart/form-data”は忘れずにform要素に設定をしてください。@crsfが利用できないバージョンの場合は{{ csrf_field() }}を利用してください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<form method="POST" action="/upload" enctype="multipart/form-data">
@csrf
{{-- {{ csrf_field() }} --}}
<input type="file" id="file" name="file" class="form-control">
<button type="submit">アップロード</button>
</form>
</body>
</html>
クロスサイトリクエストフォージェリ(CSRF)の略で、@csrfとも記述することが可能です。
ルーティングに設定した/uploadにアクセスするとファイルをアップロードするためのフォームが表示されます。
アップロードしたフィルの情報確認
作成したフォームからファイルをアップロードして、アップロードしたファイルの情報を確認してみましょう。UploadController.phpファイルにstoreメソッドを追加します。
public function store(Request $request){
dd($request->all());
}
storeメソッドを追加後、実際にファイルのアップロードを作成したフォームから行います。ここでは”アップロードファイル.pdf”という名前のファイルです。
dump&dieコマンド(dd)を実行するとアップロードしたファイルの情報を確認することができます。
array:2 [▼
"_token" => "3bSrdIPLL3alM6iH3pYJIKRDEDXnZHcmWhOi3dCK"
"file" => UploadedFile {#204 ▼
-test: false
-originalName: "アップロードファイル.pdf"
-mimeType: "application/pdf"
-error: 0
#hashName: null
path: "/private/var/folders/5h/bxvtcnj978dfmqwdkr59xvj40000gn/T"
filename: "php3fAJXn"
basename: "php3fAJXn"
pathname: "/private/var/folders/5h/bxvtcnj978dfmqwdkr59xvj40000gn/T/php3fAJXn"
extension: ""
realPath: "/private/var/folders/5h/bxvtcnj978dfmqwdkr59xvj40000gn/T/php3fAJXn"
aTime: 2018-12-31 02:23:19
mTime: 2018-12-31 02:23:19
cTime: 2018-12-31 02:23:19
inode: 1084426
size: 208312
perms: 0100600
owner: 501
group: 20
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
}
]
ddコマンドでは、フォームから送られてくるすべての情報を表示していましたが、ファイルのみの情報を表示させるためにfileメソッドを利用します。
dd($request->file('file'));
fileメソッドを利用するとmime typeやサイズの情報も確認することができます。ファイルの情報は、UploadFileインスタンスに保存されていることも下記の情報からわかります。
UploadedFile {#204 ▼
-test: false
-originalName: "アップロードファイル.pdf"
-mimeType: "application/pdf"
-error: 0
#hashName: null
path: "/private/var/folders/5h/bxvtcnj978dfmqwdkr59xvj40000gn/T"
filename: "php01V3en"
basename: "php01V3en"
pathname: "/private/var/folders/5h/bxvtcnj978dfmqwdkr59xvj40000gn/T/php01V3en"
extension: ""
realPath: "/private/var/folders/5h/bxvtcnj978dfmqwdkr59xvj40000gn/T/php01V3en"
aTime: 2018-12-31 02:26:38
mTime: 2018-12-31 02:26:38
cTime: 2018-12-31 02:26:38
inode: 1084476
size: 208312
perms: 0100600
owner: 501
group: 20
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
}
もしformタグにenctype=”multipart/form-data”の設定を忘れた場合はファイルをアップロードするとファイル名のみ表示されます。
アップロードしたファイルの保存
アップロードしたファイル情報を保持するUploadFileクラスはファイルを保存するためのstoreメソッドを持っています。先ほどdd関数で表示されたUploadFileインスタンスのstoreメソッドを利用することで、サーバ上にアップロードしたファイルを保存することができます。ファイルが保存される場所はLaravelインストールディレクトリの下にあるstorage/appです。
public function store(Request $request){
$request->file('file')->store('');
}
サーバ上でファイルが保存されているか確認します。ファイル名は、Laravel側で自動で付与されます。Laravelではたったこれだけの処理で簡単にサーバへのファイルのアップロードを行うことができます。
% pwd
/Users/mac/Desktop/laravel_upload/storage/app
% ls
1bRLVYORlvI5curaPFUVob8DVMUBpSL1D2zJcXFS.pdf
public
任意の名前をつけてファイルを保存
アップロードしたファイル名または任意の名前を付けたい場合は、storeAsメソッドを利用します。
$request->file('file')->storeAs('','upload_file.pdf');
storeAsメソッドで指定したファイル名で保存されることが確認できます。
% pwd
/Users/mac/Desktop/laravel_upload/storage/app
% ls
1bRLVYORlvI5curaPFUVob8DVMUBpSL1D2zJcXFS.pdf
public
upload_file.pdf
アップロードしたファイル名をつけて保存
UploadFileインスタンスのgetClientOriginalNameメソッドを利用すると拡張子を含め、アップロードしたファイルのファイル名を取得することができます。
$file_name = $request->file('file')->getClientOriginalName();
$request->file('file')->storeAs('',$file_name);
ここではアップロードファイル.pdfという名前のファイルをアップロードしたのでアップロードファイル.pdfとしてファイルが保存されています。日本語ファイル名も文字化けされることなく問題なく保存されることも確認できます。
% pwd
/Users/mac/Desktop/laravel_upload/storage/app
% ls
1bRLVYORlvI5curaPFUVob8DVMUBpSL1D2zJcXFS.pdf
public
upload_file.pdf
アップロードファイル.pdf
複数ファイルのアップロード
ここまでは1つのファイルのアップロード処理のみを行ってきましたが、複数のファイルのアップロードの処理を確認します。
複数ファイルのアップロードには2つの方法があります。
- 1つのフォームで複数のinput要素を設定する方法
- 一つのinput要素で複数のファイルをアップロードする方法
1つ目の方法はこれまでの方法と同じなので、ここでは2つ目の方法を説明します。
複数ファイルのアップロードを許可するためには、input要素の変更が必要です。nameをfile[]に変更し、multipleを追加しています。
<input type="file" id="file" name="file[]" class="form-control" multiple>
input要素にmultipleを追加するとファイル選択時に複数のファイルが選択可能となります。1つのファイルではなく複数のファイルを選択してください。
UploadController.phpファイルでアップロードされたファイルをddで確認します。
dd($request->file('file'));
フォームから2つのファイルを同時にアップすると下記のように配列に含まれたファイル情報が表示されます。
array:2 [▼
0 => UploadedFile {#206 ▶}
1 => UploadedFile {#212 ▶}
]
配列に保存されたファイルは、foreachで展開することで個別にファイルの保存を行うことができます。
$files = $request->file('file');
foreach($files as $file){
$file_name = $file->getClientOriginalName();
$file->storeAS('',$file_name);
}
1つのファイルでのアップロード方法から複数のファイルでのアップロード方法まで理解することができました。次はアップロードしたファイルのブラウザからアクセス方法を確認していきます。
アップロードしたファイルの閲覧
シンボリックリンクの作成
ファイルをアップロードしただけではブラウザからアップロードしたファイルを閲覧することはできません。ブラウザからサーバ上のファイルにアクセスするためには、Laravelインストールディレクトリの下にある公開用のpublicディレクトリの下に保存する必要があります。しかし、アップロードしたファイルは/storage/appの下にあるためアクセスすることができません。そのため/publicディレクトリと/storage/appディレクトリとの間でリンクを持たせる必要があります。リンクを貼ることで/publicにアクセスすると/strorage/appディレクトリにアクセスすることができるようになります。Windowsで言えばショートカットをイメージしてください。
Laravelではリンクを貼る設定を行う機能も備えています。
php artisan storage:linkを実行します。
表示されるパスは環境によって異なりますがLaravel9では実行すると以下のメッセージが表示されます。どの場所とどの場所でリンクが貼られているのかはっきり理解することができます。
$ php artisan storage:link
//Laravel11
INFO The [public/storage] link has been connected to [storage/app/public].
//Laravel9
The [/Users/mac/Desktop/laravel_upload/public/storage] link has been connected to [/Users/mac/Desktop/laravel_upload/storage/app/public].
The links have been created.
/publicディレクトリの下にstorageディレクトリが作成され、/storage/app/publicへシンボリックリンクが張られます。
$ pwd
/Users/mac/Desktop/laravel_upload/public
$ ls -l storage
lrwxr-xr-x 1 mac staff 47 12 31 11:55 storage ->/Users/mac/Desktop/laravel_upload/storage/app/public
ファイルの保存
本文書通りに動作確認を行なっているとファイルのアップロード設定が複数ファイル対応になっています。ここでは最初に説明を行なった1つのファイルのアップロード方法に戻してください。
<input type="file" id="file" name="file" class="form-control">
/storage/app/publicの下にアップロードしたファイルを保存します。ファイルを保存するためにUploadController.phpのstorsAsメソッドの変更を行います。
$file_name = $request->file('file')->getClientOriginalName();
$request->file('file')->storeAs('public',$file_name);
ファイルがstorage/app/publicディレクトリの下に保存されていることが確認できます。表示されるファイル名はアップロードしたファイルによって異なります。
$ pwd
/Users/mac/Desktop/laravel_upload/storage/app/public
$ ls
アップロードファイル.pdf
シンボリックリンクが設定されているため、public/storage/ディレクトリからもアップロードファイル.pdfファイルへアクセスすることができます。
mac$ pwd
/Users/mac/Desktop/laravel_upload/public/storage
mac$ ls
アップロードファイル.pdf
ブラウザからのファイルの閲覧
publicディレクトリに下に置いたファイルは、ブラウザからアクセスできるため、保存したファイルを閲覧してみましょう。index.blade.phpのビューファイルに下記の行を追加します。ここではアップロードファイル.pdfとしていますが各自がアップロードしたファイルを指定してください。画像ファイルをアップロードした場合はimgタグを利用してください。
<a href="/storage/アップロードファイル.pdf">アップロードファイル</a>
ブラウザで下記のように表示されます。
リンク部分をクリックするとPDFの内容がブラウザに表示されます。
Storageを使用したファイルの保存
LaravelではStorageファサードを使用してファイルの保存を行うこともできます。
storeメソッドを使用して下記のようにファイルの保存ができることを説明しました。
public function store(Request $request){
$request->file('file')->store('');
}
ここからは同様の処理をStorageファサードを利用して行なっていきます。
Storageファサードの使い方については下記の文書でより詳細に解説しています。Amazon Web ServiceのS3にファイルを保存したい場合についても説明を行なっています。
putFileメソッドによる保存
Storageファサードを使用するとuseでStorageを呼び出す必要があります。下記のようにStorageファサードを利用するとstoreメソッドと同様putFileメソッドでファイルの保存が可能です。下記の場合は/strage/appディレクトリにアップロードしたファイルが保存されます。
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class UploadController extends Controller
{
public function index(){
return view('index');
}
public function store(Request $request){
Storage::putFile('',$request->file('file'));
}
}
putFileAsメソッドによる保存
名前をつけたい場合は、putFileAsメソッドを使用します。/storage/appディレクトリにアップロードしたファイル名で保存されます。
$file_name = $request->file('file')->getClientOriginalName();
Storage::putFileAs('',$request->file('file'), $file_name);
putによる保存
putメソッドによってもファイルの保存を行うことができます。file_get_contents関数を使い文字列としてファイル内容の読み込みを行っています。
$file_name = $request->file('file')->getClientOriginalName();
Storage::put($file_name, file_get_contents($request->file('file')->getRealPath()));
上記の文字列を保存とファイルの保存の関係がわかりにくい場合は下記の操作を見ればはっきり理解できるかと思います。
Storage::put('file.txt', 'この文字列をファイルに追加');
”この文字列をファイルに追加”という内容のfile.txtファイルが作成されます。
非公開のファイルのダウンロード
storage/app/public以下に保存したファイルに対してはpublicが公開フォルダであるためブラウザからアクセスすることができます。ブラウザでは直接アクセスできないapp以下のファイルをダウンロードしたいという場合は下記の方法で行うことができます。
公開ディレクトリに保存されていないファイルは、Storage::downloadでファイルのダウンロードを行うことができます。
$filePath = 'private/profile.png';
$fileName = 'profile.png';
$mimeType = Storage::mimeType('private/profile.png');
$headers = [['Content-Type' => $mimeType]];
return Storage::download($filePath, $fileName, $headers);
ダウンロード方法はいくつかあるので、下記の文書にまとめています。
その他
ファイル名と拡張子の取得
ファイルの拡張子はextensionメソッドで取得できます。そのほかにguessExtensionメソッドやgetClientOriginalExtensionメソッドでも可能です。
拡張子を取得するだけでもさまざまなメソッドがあります。どのようなメソッドが存在するかはUploadFileクラスのソースコードを見るとわかります。ぜひ興味がある人は一度確認してみてください。
vendor/laravel/framework/src/Illuminate/Http/UploadedFile.php
- symfony/http-foundation/File/File.php
pathinfo
アップロードしたファイルのファイル名と拡張子を別々に取得したい場合はpathinfo関数を利用することもできます。pathinfoは内部で利用されています。
$file= $request->file('file')->getClientOriginalName();
$filename = pathinfo($file, PATHINFO_FILENAME);//ファイル名のみ
$extension = pathinfo($file, PATHINFO_EXTENSION);//拡張子のみ
ここまでの手順を理解することができればLaravelアプリケーションにファイルのアップロード機能を実装することができます。