关于在文件系统与数据库上存储 Laravel 文件上传的问题,以及如何在需要时存储在数据库而不是文件系统中
Posted
技术标签:
【中文标题】关于在文件系统与数据库上存储 Laravel 文件上传的问题,以及如何在需要时存储在数据库而不是文件系统中【英文标题】:Question about Storing Laravel File Uploads on File System vs. Database, and how to Store in DB instead of File System if desired 【发布时间】:2021-10-12 02:27:14 【问题描述】:刚刚开始在 Laravel 8.x 中处理文件上传。我已经构建了一个 UI 和路由以及一个控制器,并且我正在内部争论在哪里以及如何存储文件。预期文件将是 .gif、.jpg、.png、.pdf、?.docx 和可能的一些视频文件类型,但主要是 .pdf,我们可能会限制为 .pdf 只是为了使最初更容易。此外,每个文件的文件大小可能不会超过 1-2 MB,并且可能会限制为最大 10 MB。使用文件系统与使用数据库有好处也有坏处。无论如何我都想要一个数据库,所以问题是是将文件系统的路径存储在数据库中,还是将 mime_type 和其他一些信息以及文件的 BLOB 或 base64 编码版本存储在数据库中,可能是base64版本。
我喜欢使用 BLOB 或 base64 的想法,因为它们在数据库中都是自包含的。无论哪种方式,查询实际上都是相同的,因为您要么拥有原始数据,要么拥有数据库中文件数据的路径。您使用 base64 会影响大小,但对于较小的文件大小,不是很大,而且这些更容易处理,因为我想使用数据 url 在前端显示文件,或者以其他方式将 blob 转换为 dataurl js。所以,不太确定 BLOB 与 DB 中的 base64 有什么区别。
这只是背景,欢迎反馈。
我在控制器中遇到的问题可能很简单,因为我从未使用过 Laravel 文件方法。到目前为止我所拥有的就是这个,尽管我可能想将它扩展到一组文件而不是一个文件。
protected function attachToRequest(Request $request)
Log::info($request->input('parent'));
Log::info($request->file('file'));
Log::info($request->file('file')->getClientOriginalName());
Log::info($request->file('file')->getMimeType());
Log::info($request->file('file')->getRealPath());
Log::info($request->file('file')->getSize());
Log::info(var_dump($request->file('file')->get()));
因为我只是想了解 Laravel File Facade 是如何工作的,所以这很有帮助:
https://laravel.com/api/8.x/Illuminate/Support/Facades/File.html
作为一个测试用例,当我将文件发布到网络路由时,我看到类似 laravel.log 文件的内容:
2021-08-07 16:17:16] local.INFO: 2
[2021-08-07 16:17:16] local.INFO: /tmp/php3pLWBc
[2021-08-07 16:17:16] local.INFO: x.pdf
[2021-08-07 16:17:16] local.INFO: application/pdf
[2021-08-07 16:17:16] local.INFO: /tmp/php3pLWBc
[2021-08-07 16:17:16] local.INFO: 27856
[2021-08-07 16:17:16] local.INFO:
我坚持的部分是如何使用 file_get_contents 或 Facade 方法获取文件的原始数据,以便我可以将其转换为 base64 或只是 BLOB 并将其存储在数据库表中,如果我想玩这个。
我在 docker 容器中在 nginx 和 PHP 上运行 Laravel,当我使用 docker exec 检查 /tmp 目录时,我只看到一些日志文件和一堆会话 ID,我认为我的 php 信息列出了 / tmp 上传为空。
如果我愿意的话,似乎应该有一种非常简单的方法将其存储在数据库中而不是文件系统中。
我想先尝试 DB 方法,然后从 /tmp 文件夹中的任何位置以及 Laravel 的文件存储中删除上传。如果我对此不满意,我可以使用文件系统。
config/filesystems.php
'disks' => [
'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'),
'endpoint' => env('AWS_ENDPOINT'),
],
'patients' => [
'driver' => 'local',
'root' => storage_path('patients'),
'visibility' => 'public',
]
],
'links' => [
public_path('storage') => storage_path('app/public'),
],
如果我要使用文件系统,我可能想为这些文件创建另一个存储路径,例如:
'request_attachements' => [
'driver' => 'local',
'root' => storage_path('request_attachements'),
'visibility' => 'public',
]
【问题讨论】:
存储文件上传到数据库?我更喜欢将文件存储在侧存储文件夹中并仅保存文件保存的路径 这并没有真正的帮助。这样做有好处也有坏处。我想知道如何做任何一个,以便我可以设置和测试它,所以我可以选择任何一种方式。编辑问题以添加我的示例文件系统配置。如果您告诉我如何获取文件系统上的路径和原始数据,我可以继续对其进行编码以进行测试。 答案很简单——不要在所有情况下都将文件存储在数据库中。 编辑了问题以添加它。在数据库中,我将为路径和 BLOB 或 base64 提供列以适应任一选项。 如果您只想发表评论而不提供答案,我会阅读文档:laravel.com/docs/8.x/filesystem、laravel.com/api/8.x/Illuminate/Support/Facades/File.html。 【参考方案1】:这似乎回答了我问题的第一部分,对于熟悉使用 Laravel 上传文件的人来说可能很明显。
这似乎可行,因为我创建了那个“磁盘”,并且我在该目录中上传了带有 uuid 和附加文件扩展名的文件。然后我可以使用下面的内容。 $contents 是我可以base64encoode,或者不,然后作为BLOB 存储在数据库中,我也有存储盘的url。这就是我一直在寻找的,因为我无法完成代码的编写。生成的示例网址如下所示:
2/aOkWzxR7W4yH1vaCW2fbft9yY5dO0GVpJs2jHWnM.png
config/filesystems.php
'requestattachements' => [
'driver' => 'local',
'root' => storage_path('./requestattachements'),
'visibility' => 'public',
]
app/Http/Controllers/MyControllers/OrdersController.php
protected function attachToRequest(Request $request)
Log::info($request->input('parent'));
Log::info($request->file('file'));
Log::info($request->file('file')->getClientOriginalName());
Log::info($request->file('file')->getMimeType());
Log::info($request->file('file')->getRealPath());
Log::info($request->file('file')->getSize());
Storage::makeDirectory('requestattachements');
$path = $request->file('file')->store(
$request->input('parent'), 'requestattachements'
);
Log::info($path);
$contents = Storage::disk('requestattachements')->get($path);
Log::info($contents);
可选择插入数据库: DB::connection('mysql2')->table('request_attachments')->insert([** Insert stuff here . . ]);
routes/web.php
Route::middleware(['auth:sanctum', 'verified'])->post('Orders/attach_request', [OrdersController::class, 'attachToRequest']);
不过,我确实有一个问题是该存储容器中的文件是否可以通过网络访问?
我的存储文件夹结构如下图,里面有一个用php artisan storage:link创建的符号链接,基本上是:
ln -s storage/app/public public/storage
drwxrwxrwx@ app
drwxrwxrwx@ debugbar
drwxrwxrwx@ framework
drwxrwxrwx@ logs
drwxr-xr-x orderattachments
drwxr-xr-x@ requestattachements
我认为 requestattachments 等中的文件是不可访问的,除非我使用辅助函数来获取这些文件,我应该根据需要更改权限?
【讨论】:
以上是关于关于在文件系统与数据库上存储 Laravel 文件上传的问题,以及如何在需要时存储在数据库而不是文件系统中的主要内容,如果未能解决你的问题,请参考以下文章