首页 > 解决方案 > 关于在文件系统与数据库上存储 Laravel 文件上传的问题,以及如何在需要时存储在数据库而不是文件系统中

问题描述

刚刚开始在 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 与数据库中的 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 的文件存储中删除上传。如果我对此不满意,我可以使用文件系统。

配置/文件系统.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',
    ]

标签: laravelfile-uploadblobstorage

解决方案


这似乎回答了我问题的第一部分,对于熟悉使用 Laravel 上传文件的人来说可能很明显。

这似乎可行,因为我创建了那个“磁盘”,并且我在该目录中上传了带有 uuid 和附加文件扩展名的文件。然后我可以使用下面的内容。$contents是我可以base64encoode,或者不,然后作为BLOB存储在数据库中,我也有存储磁盘的url。这就是我一直在寻找的,因为我不能完成编写代码。生成的示例 url 如下所示:

2/aOkWzxR7W4yH1vaCW2fbft9yY5dO0GVpJs2jHWnM.png

配置/文件系统.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 . . ]);

路线/web.php

Route::middleware(['auth:sanctum', 'verified'])->post('Orders/attach_request', [OrdersController::class, 'attachToRequest']);

不过,我确实有一个问题是该存储容器中的文件是否可以通过网络访问?

我的存储文件夹结构如下所示,其中有一个使用 php artisan storage:link 创建的符号链接,基本上是:

ln -s 存储/应用程序/公共公共/存储

drwxrwxrwx@  app
drwxrwxrwx@  debugbar
drwxrwxrwx@  framework
drwxrwxrwx@  logs
drwxr-xr-x   orderattachments
drwxr-xr-x@  requestattachements

我认为 requestattachments 等中的文件是不可访问的,除非我使用辅助函数来获取这些文件,我应该根据需要更改权限吗?


推荐阅读