はじめに
Laravelは、Frank de Jongeによる素晴らしいFlysystem PHPパッケージのおかげで、強力なファイルシステムの抽象化を提供します。Laravel Flysystemの統合は、ローカルファイルシステム、SFTP、およびAmazon S3で作業するためのシンプルなドライバーを提供します。さらに良いことに、APIは各システムで同じであるため、ローカル開発マシンと本番サーバー間でこれらのストレージオプションを簡単に切り替えることができます。
設定
Laravelのファイルシステム設定ファイルはconfig/filesystems.php
にあります。このファイル内で、すべてのファイルシステム「ディスク」を設定できます。各ディスクは特定のストレージドライバーとストレージ場所を表します。サポートされている各ドライバーの例の設定が設定ファイルに含まれているため、ストレージの好みや資格情報を反映するように設定を変更できます。
好きなだけ多くのディスクを設定でき、同じドライバーを使用する複数のディスクを持つこともできます。
<a name="the-local-driver"></a>
### ローカルドライバー
`````local`````ドライバーを使用する場合、すべてのファイル操作は`````root`````設定ファイルで定義されたディレクトリに対して相対的です。デフォルトでは、この値は`````storage/app`````ディレクトリに設定されています。したがって、次のメソッドは`````storage/app/example.txt`````に書き込みます:
``````php
use Illuminate\Support\Facades\Storage;
Storage::disk('local')->put('example.txt', 'Contents');
`
パブリックディスク
これらのファイルをWebからアクセス可能にするには、`````public/storage`````から`````storage/app/public`````へのシンボリックリンクを作成する必要があります。このフォルダーの規則を利用することで、公開アクセス可能なファイルを1つのディレクトリに保持し、[Envoyer](https://envoyer.io)のようなゼロダウンタイムデプロイメントシステムを使用する際に、デプロイメント間で簡単に共有できます。
シンボリックリンクを作成するには、`````storage:link````` Artisanコマンドを使用できます:
``````shell
php artisan storage:link
`
ファイルが保存され、シンボリックリンクが作成されたら、asset
ヘルパーを使用してファイルへのURLを作成できます:
echo asset('storage/file.txt');
``````php
'links' => [
public_path('storage') => storage_path('app/public'),
public_path('images') => storage_path('app/images'),
],
`
``````shell
php artisan storage:unlink
`
ドライバーの前提条件
S3ドライバーの設定
S3ドライバーを使用する前に、Composerパッケージマネージャーを介してFlysystem S3パッケージをインストールする必要があります:
composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies
S3ディスク設定配列は、config/filesystems.php
設定ファイルにあります。通常、config/filesystems.php
設定ファイルで参照される次の環境変数を使用して、S3情報と資格情報を設定する必要があります:
AWS_ACCESS_KEY_ID=<your-key-id>
AWS_SECRET_ACCESS_KEY=<your-secret-access-key>
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=<your-bucket-name>
AWS_USE_PATH_STYLE_ENDPOINT=false
便利なことに、これらの環境変数はAWS CLIで使用される命名規則と一致します。
FTPドライバーの設定
FTPドライバーを使用する前に、Composerパッケージマネージャーを介してFlysystem FTPパッケージをインストールする必要があります:
composer require league/flysystem-ftp "^3.0"
LaravelのFlysystem統合はFTPと非常に相性が良いですが、フレームワークのデフォルトconfig/filesystems.php
設定ファイルにはサンプル設定が含まれていません。FTPファイルシステムを設定する必要がある場合は、以下の設定例を使用できます:
'ftp' => [
'driver' => 'ftp',
'host' => env('FTP_HOST'),
'username' => env('FTP_USERNAME'),
'password' => env('FTP_PASSWORD'),
// Optional FTP Settings...
// 'port' => env('FTP_PORT', 21),
// 'root' => env('FTP_ROOT'),
// 'passive' => true,
// 'ssl' => true,
// 'timeout' => 30,
],
SFTPドライバーの設定
SFTPドライバーを使用する前に、Composerパッケージマネージャーを介してFlysystem SFTPパッケージをインストールする必要があります:
composer require league/flysystem-sftp-v3 "^3.0"
LaravelのFlysystem統合はSFTPと非常に相性が良いですが、フレームワークのデフォルトconfig/filesystems.php
設定ファイルにはサンプル設定が含まれていません。SFTPファイルシステムを設定する必要がある場合は、以下の設定例を使用できます:
'sftp' => [
'driver' => 'sftp',
'host' => env('SFTP_HOST'),
// Settings for basic authentication...
'username' => env('SFTP_USERNAME'),
'password' => env('SFTP_PASSWORD'),
// Settings for SSH key based authentication with encryption password...
'privateKey' => env('SFTP_PRIVATE_KEY'),
'passphrase' => env('SFTP_PASSPHRASE'),
// Settings for file / directory permissions...
'visibility' => 'private', // `private` = 0600, `public` = 0644
'directory_visibility' => 'private', // `private` = 0700, `public` = 0755
// Optional SFTP Settings...
// 'hostFingerprint' => env('SFTP_HOST_FINGERPRINT'),
// 'maxTries' => 4,
// 'passphrase' => env('SFTP_PASSPHRASE'),
// 'port' => env('SFTP_PORT', 22),
// 'root' => env('SFTP_ROOT', ''),
// 'timeout' => 30,
// 'useAgent' => true,
],
スコープ付きおよび読み取り専用ファイルシステム
スコープ付きディスクを使用すると、すべてのパスが指定されたパスプレフィックスで自動的にプレフィックスされるファイルシステムを定義できます。スコープ付きファイルシステムディスクを作成する前に、Composerパッケージマネージャーを介して追加のFlysystemパッケージをインストールする必要があります:
composer require league/flysystem-path-prefixing "^3.0"
``````php
's3-videos' => [
'driver' => 'scoped',
'disk' => 's3',
'prefix' => 'path/to/videos',
],
`
「読み取り専用」ディスクを使用すると、書き込み操作を許可しないファイルシステムディスクを作成できます。read-only
設定オプションを使用する前に、Composerパッケージマネージャーを介して追加のFlysystemパッケージをインストールする必要があります:
composer require league/flysystem-read-only "^3.0"
次に、ディスクの設定配列の1つ以上にread-only
設定オプションを含めることができます:
's3-videos' => [
'driver' => 's3',
// ...
'read-only' => true,
],
Amazon S3互換ファイルシステム
デフォルトでは、アプリケーションのfilesystems
設定ファイルにはs3
ディスクの設定が含まれています。このディスクを使用してAmazon S3と対話するだけでなく、MinIOやDigitalOcean SpacesなどのS3互換ファイルストレージサービスと対話するためにも使用できます。
通常、使用するサービスの資格情報に一致するようにディスクの資格情報を更新した後、endpoint
設定オプションの値を更新するだけで済みます。このオプションの値は通常、AWS_ENDPOINT
環境変数を介して定義されます:
'endpoint' => env('AWS_ENDPOINT', 'https://minio:9000'),
MinIO
LaravelのFlysystem統合がMinIOを使用する際に適切なURLを生成するには、AWS_URL
環境変数を定義して、アプリケーションのローカルURLとバケット名をURLパスに含める必要があります:
AWS_URL=http://localhost:9000/local
<a name="obtaining-disk-instances"></a>
## ディスクインスタンスの取得
`````Storage`````ファサードを使用して、設定されたディスクのいずれかと対話できます。たとえば、ファサードの`````put`````メソッドを使用して、デフォルトディスクにアバターを保存できます。`````Storage`````ファサードで`````disk`````メソッドを最初に呼び出さずにメソッドを呼び出すと、そのメソッドは自動的にデフォルトディスクに渡されます:
``````php
use Illuminate\Support\Facades\Storage;
Storage::put('avatars/1', $content);
`
アプリケーションが複数のディスクと対話する場合、Storage
ファサードのdisk
メソッドを使用して特定のディスクのファイルで作業できます:
Storage::disk('s3')->put('avatars/1', $content);
オンデマンドディスク
時には、アプリケーションのfilesystems
設定ファイルにその設定が実際に存在しない状態で、指定された設定を使用してランタイムでディスクを作成したい場合があります。これを実現するには、Storage
ファサードのbuild
メソッドに設定配列を渡すことができます:
use Illuminate\Support\Facades\Storage;
$disk = Storage::build([
'driver' => 'local',
'root' => '/path/to/root',
]);
$disk->put('image.jpg', $content);
ファイルの取得
``````php
$contents = Storage::get('file.jpg');
`
取得しているファイルがJSONを含む場合、json
メソッドを使用してファイルを取得し、その内容をデコードできます:
$orders = Storage::json('orders.json');
``````php
if (Storage::disk('s3')->exists('file.jpg')) {
// ...
}
`
``````php
if (Storage::disk('s3')->missing('file.jpg')) {
// ...
}
`
ファイルのダウンロード
``````php
return Storage::download('file.jpg');
return Storage::download('file.jpg', $name, $headers);
`
ファイルURL
``````php
use Illuminate\Support\Facades\Storage;
$url = Storage::url('file.jpg');
`
`````local`````ドライバーを使用する場合、`````url`````の戻り値はURLエンコードされません。このため、常に有効なURLを作成する名前を使用してファイルを保存することをお勧めします。
<a name="url-host-customization"></a>
#### URLホストのカスタマイズ
`````Storage`````ファサードを使用して生成されたURLのホストを変更したい場合は、ディスクの設定配列に`````url`````オプションを追加または変更できます:
``````php
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
'throw' => false,
],
`
一時URL
``````php
use Illuminate\Support\Facades\Storage;
$url = Storage::temporaryUrl(
'file.jpg', now()->addMinutes(5)
);
`
ローカル一時URLの有効化
一時URLのサポートがlocal
ドライバーに導入される前にアプリケーションの開発を開始した場合、ローカル一時URLを有効にする必要があるかもしれません。そのためには、serve
オプションをlocal
ディスクの設定配列にconfig/filesystems.php
設定ファイル内で追加します:
'local' => [
'driver' => 'local',
'root' => storage_path('app/private'),
'serve' => true,
'throw' => false,
],
S3リクエストパラメータ
追加のS3リクエストパラメータを指定する必要がある場合、temporaryUrl
メソッドの第3引数としてリクエストパラメータの配列を渡すことができます:
$url = Storage::temporaryUrl(
'file.jpg',
now()->addMinutes(5),
[
'ResponseContentType' => 'application/octet-stream',
'ResponseContentDisposition' => 'attachment; filename=file2.jpg',
]
);
一時URLのカスタマイズ
特定のストレージディスクの一時URLの作成方法をカスタマイズする必要がある場合、buildTemporaryUrlsUsing
メソッドを使用できます。たとえば、通常一時URLをサポートしないディスクを介して保存されたファイルをダウンロードできるコントローラーがある場合に便利です。通常、このメソッドはサービスプロバイダーのboot
メソッドから呼び出されるべきです:
<?php
namespace App\Providers;
use DateTime;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Storage::disk('local')->buildTemporaryUrlsUsing(
function (string $path, DateTime $expiration, array $options) {
return URL::temporarySignedRoute(
'files.download',
$expiration,
array_merge($options, ['path' => $path])
);
}
);
}
}
一時アップロードURL
一時アップロードURLを生成する機能は、s3
ドライバーでのみサポートされています。
クライアント側アプリケーションからファイルを直接アップロードするために使用できる一時URLを生成する必要がある場合、temporaryUploadUrl
メソッドを使用できます。このメソッドは、パスとURLが期限切れになる時期を指定するDateTime
インスタンスを受け入れます。temporaryUploadUrl
メソッドは、アップロードURLとアップロードリクエストに含めるべきヘッダーを分解できる連想配列を返します:
use Illuminate\Support\Facades\Storage;
['url' => $url, 'headers' => $headers] = Storage::temporaryUploadUrl(
'file.jpg', now()->addMinutes(5)
);
このメソッドは、クライアント側アプリケーションがAmazon S3などのクラウドストレージシステムにファイルを直接アップロードする必要があるサーバーレス環境で主に便利です。
ファイルメタデータ
ファイルの読み書きに加えて、Laravelはファイル自体に関する情報も提供できます。たとえば、size
メソッドを使用して、ファイルのサイズをバイト単位で取得できます:
use Illuminate\Support\Facades\Storage;
$size = Storage::size('file.jpg');
``````php
$time = Storage::lastModified('file.jpg');
`
特定のファイルのMIMEタイプは、mimeType
メソッドを介して取得できます:
$mime = Storage::mimeType('file.jpg');
ファイルパス
``````php
use Illuminate\Support\Facades\Storage;
$path = Storage::path('file.jpg');
`
ファイルの保存
``````php
use Illuminate\Support\Facades\Storage;
Storage::put('file.jpg', $contents);
Storage::put('file.jpg', $resource);
`
書き込み失敗
もしput
メソッド(または他の「書き込み」操作)がファイルをディスクに書き込めない場合、false
が返されます:
if (! Storage::put('file.jpg', $contents)) {
// The file could not be written to disk...
}
必要に応じて、ファイルシステムディスクの設定配列内にthrow
オプションを定義できます。このオプションがtrue
として定義されている場合、put
のような「書き込み」メソッドは、書き込み操作が失敗したときにLeague\Flysystem\UnableToWriteFile
のインスタンスをスローします:
'public' => [
'driver' => 'local',
// ...
'throw' => true,
],
ファイルへの前置きおよび後置き
``````php
Storage::prepend('file.log', 'Prepended Text');
Storage::append('file.log', 'Appended Text');
`
ファイルのコピーと移動
``````php
Storage::copy('old/file.jpg', 'new/file.jpg');
Storage::move('old/file.jpg', 'new/file.jpg');
`
自動ストリーミング
ストレージへのファイルのストリーミングは、メモリ使用量を大幅に削減します。Laravelが指定されたファイルをストレージ位置に自動的にストリーミングするようにしたい場合、putFile
またはputFileAs
メソッドを使用できます。このメソッドは、Illuminate\Http\File
またはIlluminate\Http\UploadedFile
インスタンスを受け入れ、ファイルを希望の場所に自動的にストリーミングします:
use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;
// Automatically generate a unique ID for filename...
$path = Storage::putFile('photos', new File('/path/to/photo'));
// Manually specify a filename...
$path = Storage::putFileAs('photos', new File('/path/to/photo'), 'photo.jpg');
`````putFile`````および`````putFileAs`````メソッドも、保存されたファイルの「可視性」を指定する引数を受け入れます。これは、Amazon S3などのクラウドディスクにファイルを保存し、生成されたURLを介してファイルを公開アクセス可能にしたい場合に特に便利です:
``````php
Storage::putFile('photos', new File('/path/to/photo'), 'public');
`
ファイルアップロード
Webアプリケーションにおいて、ファイルを保存する最も一般的なユースケースの1つは、ユーザーがアップロードしたファイル(写真や文書など)を保存することです。Laravelは、アップロードされたファイルをstore
メソッドを使用して非常に簡単に保存できます。アップロードされたファイルを保存したいパスでstore
メソッドを呼び出します:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class UserAvatarController extends Controller
{
/**
* Update the avatar for the user.
*/
public function update(Request $request): string
{
$path = $request->file('avatar')->store('avatars');
return $path;
}
}
この例について注意すべき重要な点がいくつかあります。ディレクトリ名のみを指定し、ファイル名を指定しなかったことに注意してください。デフォルトでは、store
メソッドはファイル名として使用する一意のIDを生成します。ファイルの拡張子は、ファイルのMIMEタイプを調べることで決定されます。ファイルへのパスはstore
メソッドによって返されるため、生成されたファイル名を含むパスをデータベースに保存できます。
``````php
$path = Storage::putFile('avatars', $request->file('avatar'));
`
ファイル名の指定
保存されたファイルに自動的にファイル名が割り当てられないようにしたい場合、storeAs
メソッドを使用できます。このメソッドは、パス、ファイル名、および(オプションの)ディスクを引数として受け取ります:
$path = $request->file('avatar')->storeAs(
'avatars', $request->user()->id
);
``````php
$path = Storage::putFileAs(
'avatars', $request->file('avatar'), $request->user()->id
);
`
印刷不可能で無効なUnicode文字は、ファイルパスから自動的に削除されます。したがって、Laravelのファイルストレージメソッドに渡す前にファイルパスをサニタイズすることをお勧めします。ファイルパスはLeague\Flysystem\WhitespacePathNormalizer::normalizePath
メソッドを使用して正規化されます。
ディスクの指定
デフォルトでは、このアップロードされたファイルのstore
メソッドは、デフォルトディスクを使用します。別のディスクを指定したい場合は、store
メソッドの第2引数としてディスク名を渡します:
$path = $request->file('avatar')->store(
'avatars/'.$request->user()->id, 's3'
);
``````php
$path = $request->file('avatar')->storeAs(
'avatars',
$request->user()->id,
's3'
);
`
他のアップロードファイル情報
アップロードされたファイルの元の名前と拡張子を取得したい場合、getClientOriginalName
およびgetClientOriginalExtension
メソッドを使用できます:
$file = $request->file('avatar');
$name = $file->getClientOriginalName();
$extension = $file->getClientOriginalExtension();
ただし、getClientOriginalName
およびgetClientOriginalExtension
メソッドは安全ではないと見なされるため、ファイル名や拡張子が悪意のあるユーザーによって改ざんされる可能性があります。このため、通常はhashName
およびextension
メソッドを使用して、指定されたファイルアップロードの名前と拡張子を取得することをお勧めします:
$file = $request->file('avatar');
$name = $file->hashName(); // Generate a unique, random name...
$extension = $file->extension(); // Determine the file's extension based on the file's MIME type...
ファイルの可視性
LaravelのFlysystem統合において、「可視性」は複数のプラットフォームにわたるファイル権限の抽象化です。ファイルはpublic
またはprivate
として宣言できます。ファイルがpublic
として宣言されると、そのファイルは一般的に他の人がアクセスできるべきであることを示しています。たとえば、S3ドライバーを使用する場合、public
ファイルのURLを取得できます。
ファイルを書き込む際にput
メソッドを介して可視性を設定できます:
use Illuminate\Support\Facades\Storage;
Storage::put('file.jpg', $contents, 'public');
ファイルがすでに保存されている場合、その可視性はgetVisibility
およびsetVisibility
メソッドを介して取得および設定できます:
$visibility = Storage::getVisibility('file.jpg');
Storage::setVisibility('file.jpg', 'public');
アップロードされたファイルと対話する際には、storePublicly
およびstorePubliclyAs
メソッドを使用して、public
可視性でアップロードされたファイルを保存できます:
$path = $request->file('avatar')->storePublicly('avatars', 's3');
$path = $request->file('avatar')->storePubliclyAs(
'avatars',
$request->user()->id,
's3'
);
ローカルファイルと可視性
local
ドライバーを使用する場合、public
可視性はディレクトリの0755
権限およびファイルの0644
権限に変換されます。アプリケーションのfilesystems
設定ファイルで権限マッピングを変更できます:
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'permissions' => [
'file' => [
'public' => 0644,
'private' => 0600,
],
'dir' => [
'public' => 0755,
'private' => 0700,
],
],
'throw' => false,
],
ファイルの削除
``````php
use Illuminate\Support\Facades\Storage;
Storage::delete('file.jpg');
Storage::delete(['file.jpg', 'file2.jpg']);
`
必要に応じて、ファイルを削除するディスクを指定できます:
use Illuminate\Support\Facades\Storage;
Storage::disk('s3')->delete('path/file.jpg');
ディレクトリ
ディレクトリ内のすべてのファイルを取得
``````php
use Illuminate\Support\Facades\Storage;
$files = Storage::files($directory);
$files = Storage::allFiles($directory);
`
ディレクトリ内のすべてのディレクトリを取得
``````php
$directories = Storage::directories($directory);
$directories = Storage::allDirectories($directory);
`
ディレクトリの作成
``````php
Storage::makeDirectory($directory);
`
ディレクトリの削除
最後に、deleteDirectory
メソッドを使用して、ディレクトリとそのすべてのファイルを削除できます:
Storage::deleteDirectory($directory);
テスト
``````php
<?php
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
test('albums can be uploaded', function () {
Storage::fake('photos');
$response = $this->json('POST', '/photos', [
UploadedFile::fake()->image('photo1.jpg'),
UploadedFile::fake()->image('photo2.jpg')
]);
// Assert one or more files were stored...
Storage::disk('photos')->assertExists('photo1.jpg');
Storage::disk('photos')->assertExists(['photo1.jpg', 'photo2.jpg']);
// Assert one or more files were not stored...
Storage::disk('photos')->assertMissing('missing.jpg');
Storage::disk('photos')->assertMissing(['missing.jpg', 'non-existing.jpg']);
// Assert that a given directory is empty...
Storage::disk('photos')->assertDirectoryEmpty('/wallpapers');
});
`
<?php
namespace Tests\Feature;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class ExampleTest extends TestCase
{
public function test_albums_can_be_uploaded(): void
{
Storage::fake('photos');
$response = $this->json('POST', '/photos', [
UploadedFile::fake()->image('photo1.jpg'),
UploadedFile::fake()->image('photo2.jpg')
]);
// Assert one or more files were stored...
Storage::disk('photos')->assertExists('photo1.jpg');
Storage::disk('photos')->assertExists(['photo1.jpg', 'photo2.jpg']);
// Assert one or more files were not stored...
Storage::disk('photos')->assertMissing('missing.jpg');
Storage::disk('photos')->assertMissing(['missing.jpg', 'non-existing.jpg']);
// Assert that a given directory is empty...
Storage::disk('photos')->assertDirectoryEmpty('/wallpapers');
}
}
デフォルトでは、fake
メソッドは一時ディレクトリ内のすべてのファイルを削除します。これらのファイルを保持したい場合は、代わりに「persistentFake」メソッドを使用できます。ファイルアップロードのテストに関する詳細は、HTTPテストドキュメントのファイルアップロードに関する情報を参照してください。
<a name="custom-filesystems"></a>
## カスタムファイルシステム
LaravelのFlysystem統合は、いくつかの「ドライバー」を標準でサポートしていますが、Flysystemはこれに限定されず、多くの他のストレージシステム用のアダプターがあります。Laravelアプリケーションでこれらの追加アダプターの1つを使用したい場合は、カスタムドライバーを作成できます。
カスタムファイルシステムを定義するには、Flysystemアダプターが必要です。コミュニティが管理するDropboxアダプターをプロジェクトに追加しましょう:
``````shell
composer require spatie/flysystem-dropbox
`
次に、アプリケーションのサービスプロバイダーのboot
メソッド内でドライバーを登録できます。これを実現するには、Storage
ファサードのextend
メソッドを使用します:
<?php
namespace App\Providers;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\ServiceProvider;
use League\Flysystem\Filesystem;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ...
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Storage::extend('dropbox', function (Application $app, array $config) {
$adapter = new DropboxAdapter(new DropboxClient(
$config['authorization_token']
));
return new FilesystemAdapter(
new Filesystem($adapter, $config),
$adapter,
$config
);
});
}
}
extend
メソッドの最初の引数はドライバーの名前で、2番目は$app
および$config
変数を受け取るクロージャです。クロージャはIlluminate\Filesystem\FilesystemAdapter
のインスタンスを返す必要があります。$config
変数には、指定されたディスクのconfig/filesystems.php
で定義された値が含まれています。
拡張のサービスプロバイダーを作成して登録したら、dropbox
ドライバーをconfig/filesystems.php
設定ファイルで使用できます。