Laravelにはファイル操作にStorageという便利な機能が備わっています。Storageを使えばローカルのファイルもクラウドのファイルもFTPサーバのファイルも同じ方法で操作することができます。Storageの操作を覚えてしまえば保存先を意識することなくファイルの操作ができるので、もし使い慣れていないようならばこの機会にStorageの使い方をマスターしておきましょう。

Amazon Web ServiceのAmazon S3への保存方法についても説明しています。

LaravelのStorageとは

LaravelのStorageはFlysystemのfilesystemライブラリを利用して作られています。

Storageを利用することでローカルディスクも外部のFTPサーバもクラウドのAmazon S3もLaravelのアプリケーションから見れば同じものとして扱うこと(各接続デバイスの違いを吸収してくれる)ができ、同じメソッドを使ってファイル操作・ディレクトリ操作を行うことができます。

storageを使う場合と使わない場合
storageを使う場合と使わない場合

言葉よりも実際にFTPサーバへの接続を通して、Storageがどれほど便利なのか確認していきます。

FTPを使ってファイル一覧を取得

Storageがどのようなものか理解するためにFTPを使ってFTPサーバ上にあるファイルの一覧を取得します。

Storageはconfig/filesystems.phpを通して設定を行うので、FTPの接続情報をfilesystem.phpに記述する必要があります。

filesystems.phpのdisksプロパティに新規にftpを追加します。host, username, passwordは各環境に合わせたFTPサーバに接続するための接続情報を設定します。


  'disks' => [
        'ftp' => [
            'driver'   => 'ftp',
            'host'     => 'XXXXXX',
            'username' => 'XXXXXX',
            'password' => 'XXXXXX',
        ],
        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],

storage_path()はヘルパー関数でLaravelのインストールフォルダの直下にあるstorageの場所になりますstorage_path(‘app’)を設定した場合はプロジェクトフォルダ/storage/appの場所になります。
fukidashi

これでFTPを利用するための設定は完了です。下記のようにportの設定を含め、オプショナル設定もあります。設定項目に不安がある場合はまずffftpやFileZillaなどOS上のFTPソフトで接続できることを事前に確認した後に設定することがおすすめです。その後、各環境に合わせて適切に設定を行ってください。


  'disks' => [
        'ftp' => [
            'driver'   => 'ftp',
            'host'     => 'XXXXXX',
            'username' => 'XXXXXX',
            'password' => 'XXXXXX',
            // Optional FTP Settings...
            // 'port'     => 21,
            // 'root'     => '',
            // 'passive'  => true,
            // 'ssl'      => true,
            // 'timeout'  => 30,
        ],

tinker上でStorageのfilesメソッドを使ってFTPサーバ上のファイル一覧を取得します。実行すると下記のようにfilesメソッドでFTPサーバ上のファイル一覧を取得することができました。表示されるファイル一覧も各環境によって異なります。tinkerはartisanファイルが存在するLaravelのプロジェクトフォルダ直下で実行してください。

簡易的な動作確認を行うためにtinkerを利用しています。直接Controllerに記述して動作確認も可能です。その場合はuse Strageもしくはuse Illuminate\Support\Facades\Storageをコントローラーファイルの先頭に必要になります。
fukidashi

 $ php artisan tinker
Psy Shell v0.9.9 (PHP 7.1.23 — cli) by Justin Hileman
>>> Storage::disk('ftp')->files();
=> [
     ".bash_profile",
     ".bash_history"
   ]

diskメソッドでは、filesystem.phpのdisksプロパティにある値(ドライバ)によって接続先を変えることができます。

Laravelのローカルディスクに保存されているファイル一覧を取得する場合は、diskメソッドにlocalを入れるだけでファイル一覧を取得することができます。


>>> Storage::disk('local')->files();
=> [
     ".DS_Store",
     ".gitignore",
     "Laravel_send_email.png",
     "zxpitPfr5KXTNROYPBS7lqJIMkLHH99mbmR82oE2.png",
   ]

localドライバに設定した際にどの場所にアクセスしてファイルの一覧を取得しているのかわからない場合はfilesystems.phpを確認してください。デフォルトではLaravelのインストールフォルダ/storage/appです。

このようにdiskメソッドをftpからlocalに変更するだけで, 同じfilesメソッドを使ってファイル一覧を取得することができます。もしStorageがなければ、FTPサーバに接続する際はPHPのftp_connect関数を使って接続処理を記述する必要があったかもしれません。しかしStorageを使えばファイルの保存場所(FTPサーバ or ローカルファイル)を気にすることなくすべてローカルにファイルが存在するように同じ方法でファイルを操作することができます。

Storageの設定について

Storageの設定はfilesystem.phpで行います。先程、diskメソッドを使ってlocalとftpの切り替えを行いましたが、デフォルト値が決まっています。もし.envファイルでFILESYSTEM_DRIVERが行われていなければ、localが設定されます。デフォルトを変更したい場合は、.envファイルにFILESYSTEM_DRIVERを追加し使用したいドライバ値を設定します。


'default' => env('FILESYSTEM_DRIVER', 'local'),

デフォルト値を使用する場合は、diskメソッドをつける必要がなくファイル一覧を取得する場合は、Storage::files()で実行することができます。Storage::disk(‘local’)->files()と毎回明示しても問題はありません。

Laravelインストール直後では3つのドライバの情報がfilesystems.phpに記述されています。localとpublicとs3です。localとpublicはLaravelのローカルディスクのドライバで、s3はAmazonのs3を使用する場合に使うドライバです。

localではappをルートディレクトリとしてappディレクトリ以下のファイルやディレクトリを操作します。publicは外部からアクセス可能なapp/publicをルートディレクトリとしてそれ以下のファイル、ディレクトリを扱います。

ファイルを保存する際にディレクトリパスを設定しますが、もしディレクトリパスを設定しなければ保存したファイルは各ドライバのルートディレクトリの直下に保存されます。
fukidashi

'local' => [
    'driver' => 'local',
    'root' => storage_path('app'),
],

'public' => [
    'driver' => 'local',
    'root' => storage_path('app/public'),
    'url' => env('APP_URL').'/storage',
    'visibility' => 'public',
],

's3' => [
    'driver' => 's3',
    'key' => env('AWS_ACCESS_KEY_ID'),
    'secret' => env('AWS_SECRET_ACCESS_KEY'),
    'region' => env('AWS_DEFAULT_REGION'),
    'bucket' => env('AWS_BUCKET'),
    'url' => env('AWS_URL'),
],

Storageによるファイル操作

FTPサーバ上とローカルのファイルの操作を通して、Storageが非常にパワフルなツールであることが理解できたと思うので、ファイル操作のメソッドを確認していきます。ここから先はdiskの設定のドライバの値には依存しません。つまり、localでもpublicでもs3でも同じ操作です。

使用したいメソッドはFilesystemAdaper.phpクラスに記述されているので、APIマニュアルから確認できます。

メソッドの一覧

使用頻度が高いと考えられるもののみ抜粋しています。

  • get(‘logo.jpg’) : ファイルを取得します
  • put(‘logo.jpg’, $fileContent) : ファイルを保存します。
  • putFile(PATH, $file) : 指定したPATHにファイルを保存。名前は一意のIDです。
  • putFileAs(PATH, $file, ‘logo.jpg’) : 指定したPATHにlogo.jpgという名前ファイルを保存します。
  • exists(‘logo.jpg’) : ファイルが存在するかチェックを行います。あればtrueが返されます。
  • copy(‘logo.jpg’, ‘new_logo.jpg’) : ファイルのコピーを行います。
  • move(‘logo.jpg, ‘new_logo.jpg’) : ファイルの移動を行います。
  • delete(‘logo.jpg’) : ファイルの削除を行います。
  • makeDirectory(‘image’) : ディレクトリを作成します。
  • deleteDirectory(‘image’) : ディレクトリを削除します。
  • size(‘logo.jpg’) : ファイルのサイズを確認します。
  • files(‘public’) : publicディレクトリにあるファイルのみ表示します。
  • allFiles(‘public’) : publicディレクトリ以下のすべてのファイルとディレクトリを表示します。ファイル、ディレクトリがたくさんある場合は時間がかかります。
  • path(‘logo.jpg’) : ファイルのフルパスを表示します。ファイル名をfalseにするとrootパスが表示されます。

メソッドだけでは使用方法がわからないので、ファイルの保存と削除を通してメソッドの使用方法を確認します。

ファイルの保存

アップロードしたファイルをStorageを使用して保存します。保存には、名前がLaravelでユニークなIDが自動で振られるputFileとファイル名を指定できるputFileAsがあります。Storageを利用する場合はStorageファサードをuseで読み込む必要があります。


use Illuminate\Support\Facades\Storage;
//略

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

$path = Storage::putFile('',$request->file('file'));

$path_as = Storage::putFileAs('',$request->file('file'), $file_name);

ファイルの保存先(root設定)

localドライバとpublicドライバの保存場所はfilesystems.phpで設定されており、各ドライバのrootの設定で確認することができます。localはappでpublicはapp/publicディレクトリ下に保存されます。


'local' => [
    'driver' => 'local',
    'root' => storage_path('app'),
],

'public' => [
    'driver' => 'local',
    'root' => storage_path('app/public'),
    'url' => env('APP_URL').'/storage',
    'visibility' => 'public',
],

ftpドライバの場合は、ftpで接続した先のディレクトリが保存先になります。

visibilityとは(権限の設定)

filesystems.phpのpublicドライバの設定でvisibilityという設定値があります。visibilityによりパーミッションの設定を行うことができます。publicとprivateの2つの値を取り、MAC環境ではpublicでは644の設定、privateでは600の設定になります。


'public' => [
    'driver' => 'local',
    'root' => storage_path('app/public'),
    'url' => env('APP_URL').'/storage',
    'visibility' => 'public',
],
パーミッションとはファイルに対する読み、書き、実行の権限を設定することです。644はファイルの所有者に読み書きの権限、所有者が属するグループに読みの権限、その他に読みの権限を与えてします。600だと所有者のみに読み書きの権限を与えており、所有者以外はアクセスすることができません。publicでは644なので誰でも読み込むことができ、privateは600で所有者のみ読み込むことができます。読みには4、書きには2、実行には1が割り当てらています。読み書きを許可する6は4 + 2の結果です。
fukidashi

ファイルを保存する時には、下記のようにpublicとprivateを設定することができます。


$path = Storage::putFile('',$request->file('file'),'public');
$path = Storage::putFile('',$request->file('file'),'private');

urlとは

filesystems.phpのpublicドライバの設定でurlという設定値があります。Storage::url($file_path)で利用することができ、指定したファイルのURLを表示させることができます。


'public' => [
    'driver' => 'local',
    'root' => storage_path('app/public'),
    'url' => env('APP_URL').'/storage',
    'visibility' => 'public',
],

例えばapp/publicディレクトリの下にimagesディレクトリを作成し2つのファイルを保存します。filesメソッドでファイルの一覧を取得した後にurlメソッドを使うと外部からアクセス可能なURLを取得することができます。

Laravelではapp\publicディレクトリの下が外部からアクセス可能な場所です。どのディレクトリにファイルを保存しても外部からアクセスできるわけではありません。
fukidashi

$files = Storage::disk('public')->files('images');

foreach( $files as $file){
	echo Storage::disk('public')->url($file).'
'; }

一覧の処理で画像が保存されているURLをurlメソッドによって表示させることができます。


http://localhost/storage/images/Laravel_send_email.png
http://localhost/storage/images/Laravel_storage.png

ファイルの削除

ファイルの削除は削除したいファイルのパスを設定します。複数の場合は配列を使って削除することができます。


Storage::delete('public/laravel_logo.png');

Storage::delete(['public/laravel_logo.png','public/vue_logo.png']);

テキストファイルへの文字列の書き込み

データは保存する際にデータベースに保存することが一般的ですがデータベースのテーブルを作成することなく別の場所に情報を保存しておきたいという場合もあるかと思います。データベースの代わりにテキストファイルへ書き込みを行い情報を保存することができます。先ほどのStorageのメソッド一覧に含まれていたputメソッド利用することで簡単に行うことができます。


Storage::disk('local')->put('order_number.txt',102);

order_number.txtという名前のテキストファイルに102という数字を追加することができます。ファイルの内容を更新したい場合は再度putメソッドを利用して102を103に変更して実行するとorder_number.txtには103が上書きされて保存されることになります。保存したデータを取得したい場合はgetメソッドを利用することができます。


$number = Storage::disk('local')->get('order_number.txt');

データベースのテーブルだけではなくStorageを利用することでファイルを使ってデータの保持を行うことも可能です。

Amazon Web Service(AWS)のS3へのファイルの保存

Storageファサードを利用することでローカルディスクにファイルを保存するようにAmazon S3のバケットにファイルを保存することができます。

AWSでアカウントの作成が完了しているという前提で話を進めさせていただきます。ファイルを保存するバケットも事前に作成しておく必要があります。
fukidashi

Amazon S3にアクセスするためにはデフォルトの.envファイルに記述されているAWS関連の環境変数の設定が必要になります。


AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false

AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEYの2つの値を作成するためにはAmazonS3FullAccessポリシーを付与されたIAMユーザで認証情報でアクセスキーを作成する必要があります。

AWS_DEFAULT_REGIONについては日本であればap-northeast-1となり、AWS_BUCKETにはバケットに設定した名前を設定します。

5つのAWSに関連すると値を設定すると下記のようになります。


AWS_ACCESS_KEY_ID=BKIBRUPDEDT7UGZG3DGD
AWS_SECRET_ACCESS_KEY=NCJEloMeBe6n-8Xu0KLPo1KrWZ3rJ/C5R4fPfVl
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=reffect-image-storage
AWS_USE_PATH_STYLE_ENDPOINT=false

S3に保存したい場合はStorageのdiskにS3を設定します。


Storage::disk('s3')->putFile('',$request->file('file'));

filesystems.phpファイルにサポートされているドライバとして”local”, “ftp”, “sftp”, “s3″を記述されている通り設定項目も存在します。


'disks' => [

    'local' => [
        //略
    ],

    'public' => [
    //略
    ],

    's3' => [
        'driver' => 's3',
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION'),
        'bucket' => env('AWS_BUCKET'),
        'url' => env('AWS_URL'),
        'endpoint' => env('AWS_ENDPOINT'),
        'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
    ],
],

設定項目もありますがS3用のパッケージをインストールする必要があります。


% composer require --with-all-dependencies league/flysystem-aws-s3-v3 "^1.0"
インストールを行っていない場合にS3へのファイルを保存しようとした場合にエラーで”ErrorClass “League\Flysystem\AwsS3v3\AwsS3Adapter” not found”が表示されます。
fukidashi

パッケージを実行し下記を実行すると$request->file(‘file’)に指定したファイルがS3に保存されます。Storageファサードを利用しているのでアップロードしたファイルを扱う方法はローカルディスクの場合と同じです。


Storage::disk('s3')->putFile('',$request->file('file'));