Laravel6.x, Laravel5.8, Laravel5.7で動作確認を行っています。

Laravel6.x, Laravel5.xを使ってファイルをアップロードする方法について詳細に説明を行なっています。アップロードだけではなく、アップロードしたファイルのブラウザからの閲覧方法についても説明を行なっているので、ファイルのアップロード機能を使ったアプリを開発する際の参考にしてください。

アップロードフォームの作成

ファイルをアップロードするためには、フォームの作成を行う必要があります。フォームを表示、ファイルをアップロードするためのルーティングをweb.phpに追加します。


Route::resource('/upload', 'UploadController');

web.phpで指定したコントローラーUploadControllerをphp artisanコマンドを利用して作成します。


$ php artisan make:controller UploadController

作成したファイルに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ファイルを作成し、ファイルをアップロードするためのフォームを作成します。

ファイルのアップロードを行う場合は、enctype=”multipart/form-data”は忘れずにform要素に設定をしてください。


<!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_field() }}

	<input type="file" id="file" name="file" class="form-control">

	<button type="submit">アップロード</button>

	</form>

</body>
</html>

ルーティングに設定した/uploadにアクセスするとファイルをアップロードするためのフォームが表示されます。

アップロードフォーム

アップロードフォーム

ブラウザでアクセスする前にはphp artisan serveを実行して開発サーバを起動さえておく必要があります。

アップロードしたフィルの情報確認

作成したフォームからファイルをアップロードして、アップロードしたファイルの情報を確認してみましょう。UploadControllerファイルに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メソッドの中のfileという文字列はフォームのinput要素のnameをfileに設定しているためです。input要素のnameをpdfに変更するとfile(‘pdf’)に変更する必要があります。

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
}

アップロードしたファイルの保存

アップロードしたファイル情報を保持するUploadFileクラスはファイルを保存するためのstoreメソッドを持っています。storeメソッドを利用することで、サーバ上にアップロードしたファイルを保存することができます。ファイルが保存される場所はLaravelインストールディレクトリの下にあるstorage/appです。


public function store(Request $request){

   $request->file('file')->store('');
		
}
storeメソッドにはパスを設定することができます。もしstore(‘test’)を設定するとstorage/appの下にtestディレクトリが作成されそこにファイルが保存されます。

サーバ上でファイルが保存されているか確認します。ファイル名は、Laravel側で自動で付与されます。


mac$ pwd
/Users/mac/Documents/laravel/storage/app
mac$ ls
1bRLVYORlvI5curaPFUVob8DVMUBpSL1D2zJcXFS.pdf
public

任意の名前をつけてファイルを保存

アップロードしたファイル名または任意の名前を付けたい場合は、storeAsメソッドを利用します。


$request->file('file')->storeAs('','upload_file.pdf');

storeAsメソッドで指定したファイル名で保存されることが確認できます。


mac$ pwd
/Users/mac/Documents/laravel/storage/app
mac$ ls
1bRLVYORlvI5curaPFUVob8DVMUBpSL1D2zJcXFS.pdf
public
upload_file.pdf

アップロードしたファイル名をつけて保存

getClientOriginalNameメソッドを利用すると拡張子を含め、アップロードしたファイルのファイル名を取得することができます。


$file_name = $request->file('file')->getClientOriginalName();

$request->file('file')->storeAs('',$file_name);

ここではアップロードファイル.pdfという名前のファイルをアップロードしたのでアップロードファイル.pdfとしてファイルが保存されています。日本語ファイル名も文字化けされることなく問題なく保存されることも確認できます。


mac$ pwd
/Users/mac/Documents/laravel/storage/app
mac$ ls
1bRLVYORlvI5curaPFUVob8DVMUBpSL1D2zJcXFS.pdf
public
upload_file.pdf
アップロードファイル.pdf
storeメソッドもstoreAsメソッドも戻り値は保存したファイルのパスです。

複数ファイルのアップロード

ここまでは1つのファイルのアップロード処理のみを行ってきましたが、複数のファイルのアップロードの処理を確認します。複数ファイルのアップロードには2つの方法があり、1つは1つのフォームで複数のinput要素を設定する方法、もう一つは一つのinput要素で複数のファイルをアップロードする方法です。前者の方法はこれまでの方法と同じなので、ここでは後者の方法を説明します。

前者の場合はinput要素のnameに複数の異なる名前をつければ複数のファイルでも独立してアップロードできます。

複数ファイルのアップロードを許可するためには、input要素の変更が必要です。nameをfile[]、mltipleを追加しています。


<input type="file" id="file" name="file[]" class="form-control" multiple>

input要素にmultipleを追加するとファイル選択時に複数のファイルが選択可能となります。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);

}

アップロードしたファイルの閲覧

シンボリックリンクの作成

アップロードしただけでは、ブラウザからアップロードしたファイルを閲覧することはできません。ブラウザからサーバ上のファイルにアクセスするためには、Laravelインストールディレクトリの下にあるpublicディレクトリの下に保存する必要があります。しかし、アップロードしたファイルは/storage/appの下にあるためアクセスすることができません。/publicディレクトリと/storage/appディレクトリとの間でリンクを持たせる必要があります。

Laravelではリンクを貼る設定を行う機能も備えています。

php artisan storage:linkを実行します。


$ php artisan storage:link
The [public/storage] directory has been linked.

/publicディレクトリの下にstorageディレクトリが作成され、/storage/app/publicへリンボクンクリンクが張られます。


$ pwd
/Users/mac/Documents/laravel/public
$ ls -l storage
lrwxr-xr-x  1 mac  staff  47 12 31 11:55 storage -> /Users/mac/Documents/laravel/storage/app/public
シンボリックリンクが張られることにより、/storage/app/publicの下にupload.pdfファイルを保存すると/public/storageからupload.pdfにアクセス可能となります。

ファイルの保存

本文書通りに動作確認を行なっているとファイルのアップロード設定が複数ファイル対応になっています。ここでは最初に説明を行なった1つのファイルのアップロード方法に戻してください。

/storage/app/publicの下にアップロードしたファイルを保存します。ファイルを保存するためにUploadController.phpのstorsAsメソッドの変更を行います。


$file_name = $request->file('file')->getClientOriginalName();

$request->file('file')->storeAs('public',$file_name);
storeAsメソッドでは、storage/appディレクトリにファイルが保存されるため、publicを設定するとstorage/app/publicにファイルが保存されます。

ファイルがstorage/app/publicディレクトリの下に保存されていることが確認できます。


$ pwd
/Users/mac/Documents/laravel/storage/app/public
$ ls
アップロードファイル.pdf

シンボリックリンクが設定されているため、public/storage/ディレクトリからもアップロードファイル.pdfファイルへアクセスすることができます。


mac$ pwd
/Users/mac/Documents/laravel/public/storage
mac$ ls
アップロードファイル.pdf

ブラウザからのファイルの閲覧

publicディレクトリに下に置いたファイルは、ブラウザからアクセスできるため、保存したファイルを閲覧してみましょう。index.blade.phpのビューファイルに下記の行を追加します。


<a href="/storage/upload_file.pdf">アップロードファイル</a>

ブラウザで下記のように表示されます。

アップロードファイルのリンク表示

アップロードファイルのリンク表示

リンク部分をクリックするとPDFの内容がブラウザに表示されます。

リンクからPDFファイルの中身を確認

リンクからPDFファイルの中身を確認

Storageを使用したファイルの保存

LaravelではStorageファサードを使用してファイルの保存を行うこともできます。

storeメソッドを使用して下記のようにファイルの保存ができることを説明しました。ここからは同様の処理をStorageファサードを利用して行なっていきます。


public function store(Request $request){

   $request->file('file')->store('');
		
}

putFileメソッドによる保存

Storageファサードを使用するとuseでStorageを呼び出す必要があります。下記のようにStorageファサードを利用するとstoreメソッドと同様putFileメソッドでファイルの保存が可能です。


namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class UploadController extends Controller
{
    public function store(Request $request){
 
    	Storage::putFile('',$request->file('file'));

    }  	
}

putFileAsメソッドによる保存

名前をつけたい場合は、putFileAsメソッドを使用します。


$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以下のファイルをダウンロードしたいという場合は下記の方法で行うことができます。

事前にアップロードしたファイルをapp/storage/privateディレクトリの下にprofile.pngという名前で保存しています。

公開ディレクトリに保存されていないファイルは、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);

ダウンロード方法はいくつかあるので、下記の文書にまとめています。

その他

ファイル名と拡張子の取得

アップロードしたファイルのファイル名と拡張子を別々に取得したい場合はpathinfo関数を利用することができます。


$file= $request->file('file')->getClientOriginalName();

$filename = pathinfo($file, PATHINFO_FILENAME);//ファイル名のみ

$extension = pathinfo($file, PATHINFO_EXTENSION);//拡張子のみ