文件存储
简介
你的应用需要存各种文件:用户上传的头像、生成的 PDF 报表、系统日志、备份文件……这些文件可能存在本地服务器、可能存在 S3 云存储、也可能存在 SFTP 服务器上。如果每种存储方式都要写不同的代码,维护起来会很痛苦。
Laravel 基于 Flysystem PHP 包提供了统一的文件系统抽象——不管文件存在哪里,API 都一样。本地磁盘、SFTP、Amazon S3 之间切换只需改一行配置,代码完全不用动。
每个存储位置在 Laravel 中叫一个磁盘(disk),在 config/filesystems.php 中配置。你可以在本地开发用 local 磁盘,生产环境用 s3 磁盘,切换只需改 .env 文件中的 FILESYSTEM_DISK 配置。
配置
Laravel 的文件系统配置文件在 config/filesystems.php。在这个文件里你可以配置所有磁盘,每个磁盘代表一个存储驱动和存储位置。配置文件中包含了每种支持驱动的示例配置,你只需根据自己的存储需求和凭据修改即可。
local驱动:文件存在运行 Laravel 的服务器本地sftp驱动:通过 SSH 密钥连接 FTP 服务器s3驱动:写入 Amazon S3 云存储
信息
你可以配置任意多个磁盘,甚至多个磁盘使用同一种驱动。比如一个 S3 磁盘存用户上传文件,另一个 S3 磁盘存系统备份。
本地驱动
使用 local 驱动时,所有文件操作都相对于 filesystems 配置文件中定义的 root 目录。默认值是 storage/app/private。所以下面的代码会把文件写到 storage/app/private/example.txt:
use Illuminate\Support\Facades\Storage;
// 把生成的报表存到本地
Storage::disk('local')->put('reports/2024-01.json', json_encode($reportData));
公共磁盘
public 磁盘用于存放需要公开访问的文件(用户头像、上传图片等)。默认使用 local 驱动,文件存在 storage/app/public。
但 storage/app/public 不在 Web 可访问的 public 目录下,用户无法直接通过 URL 访问。需要创建一个符号链接,从 public/storage 指向 storage/app/public:
php artisan storage:link
创建符号链接后,存储在 storage/app/public/avatars/1.jpg 的文件就可以通过 http://your-app.test/storage/avatars/1.jpg 访问。
你还可以用 asset() 辅助函数生成完整的 URL:
// 生成头像的公开访问 URL
$url = asset('storage/avatars/1.jpg');
如果需要额外的符号链接(比如把 storage/app/images 也公开),在 filesystems.php 中配置:
'links' => [
public_path('storage') => storage_path('app/public'),
public_path('images') => storage_path('app/images'),
],
每次运行 storage:link 时所有配置的链接都会被创建。用 storage:unlink 删除:
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 中,通常通过环境变量配置凭据(变量名与 AWS CLI 一致,方便复用):
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
FTP 驱动配置
安装 FTP 驱动包:
composer require league/flysystem-ftp "^3.0"
框架默认配置文件不含 FTP 示例,如果需要,在 config/filesystems.php 中添加:
'ftp' => [
'driver' => 'ftp',
'host' => env('FTP_HOST'),
'username' => env('FTP_USERNAME'),
'password' => env('FTP_PASSWORD'),
// 可选配置...
// 'port' => env('FTP_PORT', 21),
// 'root' => env('FTP_ROOT'),
// 'passive' => true,
// 'ssl' => true,
// 'timeout' => 30,
],
SFTP 驱动配置
安装 SFTP 驱动包:
composer require league/flysystem-sftp "^3.0"
框架默认配置文件不含 SFTP 示例,如果需要,在 config/filesystems.php 中添加:
'sftp' => [
'driver' => 'sftp',
'host' => env('SFTP_HOST'),
// 基本认证...
'username' => env('SFTP_USERNAME'),
'password' => env('SFTP_PASSWORD'),
// SSH 密钥认证...
'privateKey' => env('SFTP_PRIVATE_KEY'),
'passphrase' => env('SFTP_PASSPHRASE'),
// 文件/目录权限...
'visibility' => 'private', // `private` = 0600, `public` = 0644
'directory_visibility' => 'private', // `private` = 0700, `public` = 0755
// 可选配置...
// 'hostFingerprint' => env('SFTP_HOST_FINGERPRINT'),
// 'maxTries' => 4,
// 'port' => env('SFTP_PORT', 22),
// 'root' => env('SFTP_ROOT', ''),
// 'timeout' => 30,
// 'useAgent' => true,
],
作用域与只读文件系统
如果你有一个 S3 磁盘,但想让某个目录(比如 path/to/videos)有独立的磁盘配置,可以用 scoped 驱动创建一个作用域磁盘——所有路径自动加上指定前缀:
's3-videos' => [
'driver' => 'scoped',
'disk' => 's3',
'prefix' => 'path/to/videos',
],
这样 Storage::disk('s3-videos')->put('intro.mp4', $content) 实际写入的是 S3 上的 path/to/videos/intro.mp4。
如果需要一个只读磁盘(防止误写),安装 flysystem-read-only 包后在磁盘配置中加 'read-only' => true:
composer require league/flysystem-read-only "^3.0"
's3-videos' => [
'driver' => 's3',
// ...
'read-only' => true, // 这个磁盘只能读不能写
],
Amazon S3 兼容文件系统
S3 驱动不仅支持 Amazon S3,还支持任何 S3 兼容的存储服务,如 RustFS、DigitalOcean Spaces、Cloudflare R2 等。只需修改 endpoint 配置指向服务地址:
'endpoint' => env('AWS_ENDPOINT', 'https://rustfs:9000'),
获取磁盘实例
用 Storage 门面操作文件。不指定磁盘时使用默认磁盘(通过 FILESYSTEM_DISK 环境变量配置):
use Illuminate\Support\Facades\Storage;
// 存到默认磁盘
Storage::put('avatars/1.jpg', $content);
操作多个磁盘时用 disk() 方法指定:
// 用户头像存到 public 磁盘(本地,公开访问)
Storage::disk('public')->put('avatars/1.jpg', $content);
// 数据库备份存到 s3 磁盘(云存储,长期保存)
Storage::disk('s3')->put('backups/db-2024-01.sql', $backupContent);
按需创建磁盘
有时候你想在运行时临时创建一个磁盘,不想写在配置文件里。比如让用户指定一个自定义的存储路径。用 Storage::build() 方法传入配置数组即可:
use Illuminate\Support\Facades\Storage;
// 临时创建一个本地磁盘,指向指定目录
$disk = Storage::build([
'driver' => 'local',
'root' => '/var/www/shared-assets',
]);
$disk->put('logo.png', $content);
读取文件
用 get() 方法读取文件内容,返回原始字符串:
// 读取系统配置文件
$config = Storage::get('config/settings.json');
如果文件是 JSON 格式,用 json() 方法一步读取并解码:
// 读取并解码订单数据
$orders = Storage::json('orders/2024-01.json');
// 返回的是数组,不需要再 json_decode
用 exists() 检查文件是否存在,missing() 检查文件是否不存在:
// 用户请求下载文件前先检查是否存在
if (Storage::disk('s3')->exists('reports/' . $userId . '/2024-01.pdf')) {
return Storage::disk('s3')->download('reports/' . $userId . '/2024-01.pdf');
}
// 或者反向检查
if (Storage::disk('s3')->missing('reports/' . $userId . '/2024-01.pdf')) {
abort(404, '报表尚未生成');
}
下载文件
download() 方法生成一个强制浏览器下载的 HTTP 响应。第二个参数指定用户看到的文件名,第三个参数传递 HTTP 头:
// 用户下载发票 — 用原始文件名
return Storage::download('invoices/INV-2024-001.pdf');
// 指定下载时显示的文件名和 headers
return Storage::download(
'invoices/INV-2024-001.pdf',
'发票_2024年1月.pdf',
['Content-Type' => 'application/pdf']
);
文件 URL
用 url() 方法获取文件的访问 URL。local 驱动返回相对路径(如 /storage/file.jpg),s3 驱动返回完整的远程 URL:
use Illuminate\Support\Facades\Storage;
// 获取用户头像的访问 URL
// local 驱动:返回 /storage/avatars/1.jpg
// s3 驱动:返回 https://your-bucket.s3.amazonaws.com/avatars/1.jpg
$url = Storage::url('avatars/1.jpg');
使用 local 驱动时,公开访问的文件必须放在 storage/app/public 目录,并且需要创建符号链接。
注意
使用 local 驱动时,url() 返回值不会做 URL 编码。建议存储文件时使用能生成合法 URL 的文件名(避免中文、空格等特殊字符)。
URL 主机自定义
如果你想修改 url() 生成的 URL 主机(比如用了 CDN),在磁盘配置中添加 url 选项:
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage', // 所有 URL 都以这个为前缀
'visibility' => 'public',
'throw' => false,
],
临时 URL
有时候你想生成一个有时效性的文件访问链接——比如给客户预览一份合同,5 分钟后链接失效。用 temporaryUrl() 方法(支持 local 和 s3 驱动):
use Illuminate\Support\Facades\Storage;
// 生成 5 分钟有效的临时链接
$url = Storage::temporaryUrl(
'contracts/client-001.pdf',
now()->plus(minutes: 5)
);
// 链接过期后自动失效,客户无法再访问
启用本地临时 URL
如果你的项目是在 local 驱动支持临时 URL 功能之前创建的,需要在 local 磁盘配置中添加 serve 选项才能使用临时 URL:
'local' => [
'driver' => 'local',
'root' => storage_path('app/private'),
'serve' => true,
'throw' => false,
],
S3 请求参数
使用 S3 时,可以通过第三个参数指定 S3 请求参数,比如强制下载而非预览:
$url = Storage::temporaryUrl(
'reports/2024-01.pdf',
now()->plus(minutes: 5),
[
'ResponseContentType' => 'application/octet-stream',
'ResponseContentDisposition' => 'attachment; filename=report.pdf',
]
);
自定义临时 URL
如果你的磁盘驱动不支持临时 URL(比如 FTP),但你想让用户通过你的应用下载文件,可以用 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
{
public function boot(): void
{
// 为 local 磁盘自定义临时 URL 生成逻辑
// 生成一个签名路由 URL,由你的控制器处理下载
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 和 local 驱动。
在 Serverless 环境中,你可能想让前端直接上传文件到 S3,不经过你的服务器——省带宽、省时间。用 temporaryUploadUrl() 生成一个临时上传 URL:
use Illuminate\Support\Facades\Storage;
// 生成一个 5 分钟有效的上传 URL
['url' => $url, 'headers' => $headers] = Storage::temporaryUploadUrl(
'avatars/user-1.jpg',
now()->plus(minutes: 5)
);
// 把 $url 和 $headers 返回给前端,前端直接 PUT 文件到 S3
// 前端代码示例(JavaScript):
// fetch(url, { method: 'PUT', headers, body: file })
文件元信息
除了读写文件,Laravel 还能获取文件的基本信息:
use Illuminate\Support\Facades\Storage;
// 文件大小(字节)
$size = Storage::size('reports/2024-01.pdf'); // 例如:1048576(1MB)
// 最后修改时间(UNIX 时间戳)
$time = Storage::lastModified('reports/2024-01.pdf'); // 例如:1704067200
// MIME 类型
$mime = Storage::mimeType('reports/2024-01.pdf'); // 例如:application/pdf
文件路径
用 path() 方法获取文件路径。local 驱动返回绝对路径,s3 驱动返回 S3 桶中的相对路径:
use Illuminate\Support\Facades\Storage;
// local 驱动:返回 /var/www/storage/app/private/reports/2024-01.pdf
$path = Storage::path('reports/2024-01.pdf');
// s3 驱动:返回 reports/2024-01.pdf
$path = Storage::disk('s3')->path('reports/2024-01.pdf');
存储文件
用 put() 方法存储文件内容。除了字符串,还可以传入 PHP 资源流(stream),Flysystem 会用底层流式传输,适合大文件:
use Illuminate\Support\Facades\Storage;
// 存储字符串内容
Storage::put('config/settings.json', json_encode($settings));
// 存储文件流(适合大文件,内存占用低)
$stream = fopen('/tmp/large-file.zip', 'r');
Storage::put('backups/large-file.zip', $stream);
fclose($stream);
写入失败处理
put() 等写入方法在失败时返回 false。比如磁盘满了、权限不对:
if (! Storage::put('reports/2024-01.json', $content)) {
// 写入失败,记录日志或通知运维
Log::error('报表存储失败', ['file' => 'reports/2024-01.json']);
}
如果你希望写入失败时直接抛异常(而不是返回 false),在磁盘配置中设置 'throw' => true:
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'throw' => true, // 写入失败时抛出 League\Flysystem\UnableToWriteFile 异常
],
前置和追加写入
prepend() 在文件开头插入内容,append() 在文件末尾追加内容。常用于日志文件:
// 日志文件追加一条记录
Storage::append('logs/app.log', now()->format('Y-m-d H:i:s') . ' 用户登录');
// 在文件开头插入最新记录(最新的在最前面)
Storage::prepend('logs/app.log', now()->format('Y-m-d H:i:s') . ' 用户注销');
复制和移动文件
copy() 复制文件到新位置,move() 移动/重命名文件:
// 把临时文件复制到正式目录
Storage::copy('temp/upload-001.jpg', 'photos/user-1.jpg');
// 把文件从旧目录移到新目录(原位置删除)
Storage::move('pending/invoice-001.pdf', 'approved/invoice-001.pdf');
自动流式传输
对于大文件上传,流式传输能显著降低内存占用。putFile() 和 putFileAs() 方法接收 Illuminate\Http\File 或 Illuminate\Http\UploadedFile 实例,自动以流式方式传输:
use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;
// 自动生成唯一文件名
$path = Storage::putFile('photos', new File('/tmp/photo.jpg'));
// 返回类似:photos/a1b2c3d4e5f6.jpg
// 手动指定文件名
$path = Storage::putFileAs('photos', new File('/tmp/photo.jpg'), 'cover.jpg');
// 返回:photos/cover.jpg
putFile() 只需指定目录名,文件名由框架自动生成唯一 ID。文件扩展名根据 MIME 类型自动推断。返回值是完整路径(含生成的文件名),你可以存到数据库里。
也可以指定可见性(对 S3 等云存储有用):
// 存为公开文件,可通过 URL 直接访问
Storage::putFile('photos', new File('/tmp/photo.jpg'), 'public');
文件上传
Web 应用最常见的文件存储场景就是用户上传——头像、图片、文档等。Laravel 让存储上传文件变得非常简单。用上传文件实例的 store() 方法,指定存储目录:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
class UserAvatarController extends Controller
{
/**
* 更新用户头像。
*/
public function update(Request $request, User $user): RedirectResponse
{
$request->validate([
'avatar' => 'required|image|max:2048', // 必须是图片,最大 2MB
]);
// store() 自动生成唯一文件名,返回完整路径
$path = $request->file('avatar')->store('avatars');
// 把路径存到用户表
$user->update(['avatar_path' => $path]);
return back()->with('status', '头像更新成功!');
}
}
store() 和 Storage 门面的 putFile() 效果一样:
$path = Storage::putFile('avatars', $request->file('avatar'));
指定文件名
如果你不想让框架自动生成文件名(比如用用户 ID 作为文件名),用 storeAs() 方法:
// 用用户 ID 作为文件名,自动推断扩展名
$path = $request->file('avatar')->storeAs(
'avatars',
$request->user()->id
);
// 返回类似:avatars/42.jpg
用 Storage 门面的 putFileAs() 方法效果一样:
$path = Storage::putFileAs(
'avatars',
$request->file('avatar'),
$request->user()->id
);
注意
文件路径中的不可打印字符和无效 Unicode 字符会被自动清除。建议在传入文件存储方法前对路径做清理。路径标准化使用 League\Flysystem\WhitespacePathNormalizer::normalizePath 方法。
指定磁盘
默认使用 FILESYSTEM_DISK 配置的磁盘。指定其他磁盘作为第二个参数传给 store():
// 头像存到 S3(生产环境推荐云存储)
$path = $request->file('avatar')->store(
'avatars/' . $request->user()->id,
's3'
);
storeAs() 的磁盘名作为第三个参数:
$path = $request->file('avatar')->storeAs(
'avatars',
$request->user()->id,
's3'
);
获取上传文件信息
获取上传文件的原始文件名和扩展名:
$file = $request->file('avatar');
// 用户上传时的原始文件名(如 "我的头像.jpg")
$name = $file->getClientOriginalName();
// 原始扩展名(如 "jpg")
$extension = $file->getClientOriginalExtension();
注意
getClientOriginalName() 和 getClientOriginalExtension() 被视为不安全——文件名和扩展名可能被恶意用户篡改。推荐用 hashName() 和 extension():
$file = $request->file('avatar');
// 生成唯一的随机文件名(安全)
$name = $file->hashName(); // 如:a1b2c3d4e5f6.jpg
// 根据 MIME 类型推断扩展名(安全)
$extension = $file->extension(); // 如:jpg
文件可见性
可见性是跨平台的文件权限抽象。文件可以声明为 public(公开访问)或 private(私有)。使用 S3 时,public 文件可通过 URL 直接访问。
写入时指定可见性:
use Illuminate\Support\Facades\Storage;
// 存为公开文件(可通过 URL 访问)
Storage::put('banners/promo.jpg', $content, 'public');
文件已存储后,用 getVisibility() 读取、setVisibility() 修改:
// 检查文件当前可见性
$visibility = Storage::getVisibility('banners/promo.jpg'); // 'public' 或 'private'
// 修改为私有
Storage::setVisibility('banners/promo.jpg', 'private');
处理上传文件时,用 storePublicly() 或 storePubliclyAs() 以公开可见性存储:
// 用户头像需要公开访问,存到 S3
$path = $request->file('avatar')->storePublicly('avatars', 's3');
// 指定文件名
$path = $request->file('avatar')->storePubliclyAs(
'avatars',
$request->user()->id,
's3'
);
图片处理
如果需要在存储前对图片做缩放、裁剪、格式转换,可以用 Laravel 的图片处理功能:
// 用户上传头像后:裁剪为 400x400、转 WebP 格式、公开存储
$path = $request->image('avatar')
->cover(400, 400) // 裁剪为 400x400
->toWebp() // 转为 WebP 格式(体积更小)
->storePublicly('avatars', 'public');
也可以从已存储的文件创建图片实例进行操作:
// 从 public 磁盘读取已有图片并处理
$image = Storage::disk('public')->image('avatars/photo.jpg');
本地文件与可见性
使用 local 驱动时,public 可见性对应目录权限 0755、文件权限 0644;private 对应目录 0700、文件 0600。可以在 filesystems.php 中自定义权限映射:
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'permissions' => [
'file' => [
'public' => 0644,
'private' => 0600,
],
'dir' => [
'public' => 0755,
'private' => 0700,
],
],
'throw' => false,
],
删除文件
delete() 方法接受单个文件名或文件名数组:
use Illuminate\Support\Facades\Storage;
// 删除单个文件
Storage::delete('avatars/old-photo.jpg');
// 批量删除
Storage::delete(['temp/file1.jpg', 'temp/file2.jpg', 'temp/file3.jpg']);
指定磁盘删除:
// 从 S3 删除旧备份
Storage::disk('s3')->delete('backups/db-2023-12.sql');
目录
获取目录下所有文件
files() 返回指定目录下的文件列表(不含子目录),allFiles() 递归包含子目录中的文件:
use Illuminate\Support\Facades\Storage;
// 获取 invoices 目录下的文件(不含子目录)
$files = Storage::files('invoices');
// 递归获取所有文件(含子目录)
$files = Storage::allFiles('invoices');
获取子目录列表
directories() 返回指定目录下的子目录,allDirectories() 递归包含所有层级的子目录:
// 获取 photos 下的直接子目录
$dirs = Storage::directories('photos');
// 递归获取所有子目录
$dirs = Storage::allDirectories('photos');
创建目录
makeDirectory() 创建目录(含所有需要的父目录):
// 按年月创建报表目录
Storage::makeDirectory('reports/2024/01');
删除目录
deleteDirectory() 删除目录及其下所有文件:
// 清理过期的临时文件目录
Storage::deleteDirectory('temp/uploads');
测试
测试文件上传时,用 Storage::fake() 创建一个假的磁盘(文件存在临时目录,测试后自动清理),配合 UploadedFile::fake() 生成假文件,让测试不依赖真实文件系统:
<?php
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
test('用户可以上传头像', function () {
Storage::fake('public'); // 用假磁盘替代真实的 public 磁盘
$user = User::factory()->create();
// 模拟上传一张假图片
$response = $this->actingAs($user)
->post('/api/avatar', [
'avatar' => UploadedFile::fake()->image('avatar.jpg', 400, 400),
]);
$response->assertStatus(200);
// 断言文件已存储
Storage::disk('public')->assertExists('avatars/' . $user->id . '.jpg');
// 断言文件不存在
Storage::disk('public')->assertMissing('avatars/old.jpg');
// 断言目录下文件数量
Storage::disk('public')->assertCount('avatars', 1);
// 断言目录为空
Storage::disk('public')->assertDirectoryEmpty('temp');
// 断言整个磁盘没有文件
Storage::disk('public')->assertEmpty();
});
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class AvatarUploadTest extends TestCase
{
public function test_用户可以上传头像(): void
{
Storage::fake('public');
$user = User::factory()->create();
$response = $this->actingAs($user)
->post('/api/avatar', [
'avatar' => UploadedFile::fake()->image('avatar.jpg', 400, 400),
]);
$response->assertStatus(200);
Storage::disk('public')->assertExists('avatars/' . $user->id . '.jpg');
Storage::disk('public')->assertMissing('avatars/old.jpg');
Storage::disk('public')->assertCount('avatars', 1);
Storage::disk('public')->assertDirectoryEmpty('temp');
Storage::disk('public')->assertEmpty();
}
}
默认 fake() 测试后删除临时文件。如果想保留(调试用),用 persistentFake()。更多文件上传测试信息请查阅 HTTP 测试文档。
注意
image() 方法(生成假图片)需要 PHP 安装 GD 扩展。
自定义文件系统
Laravel 内置了 local、s3、sftp、ftp 等驱动,但 Flysystem 还有很多社区适配器。如果你想用 Dropbox、Google Drive 等存储服务,可以自定义驱动。
以 Dropbox 为例,先安装社区适配器:
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
{
public function register(): void
{
// ...
}
public function boot(): void
{
// 注册 dropbox 驱动
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() 的第一个参数是驱动名,第二个是闭包,接收 $app 和 $config(来自 config/filesystems.php 中该磁盘的配置),返回 FilesystemAdapter 实例。
注册后,就可以在 config/filesystems.php 中使用 dropbox 驱动了:
'dropbox' => [
'driver' => 'dropbox',
'authorization_token' => env('DROPBOX_TOKEN'),
],
然后正常使用:Storage::disk('dropbox')->put('file.txt', $content);