猿问

Laravel 从 php 输出缓冲区 VS 下载文件。私人存储文件夹| 安全

用户可以下载 CSV 格式的查询结果。文件很小(几 KB),但内容很重要。


第一种方法是使用 php 输出缓冲区php://:


$callback = function() use ($result, $columns) {

    $file = fopen('php://output', 'w');

    fputcsv($file, $columns);


    foreach($result as $res) {

        fputcsv($file, array($res->from_user, $res->to_user, $res->message, $res->date_added));

    }

    fclose($file);

};


return response()->stream($callback, 200, $headers);

第二种方法是在 laravel 存储系统中创建一个新文件夹并将其设置为私有并从那里下载文件。您甚至可以在下载后删除文件:


'csv' => [

    'driver' => 'local',

    'root' => storage_path('csv'),

    'visibility' => 'private',

],

这是创建/下载代码:


$file = fopen('../storage/csv/file.csv', 'w');

fputcsv($file, $columns);


foreach($result as $res) {

    fputcsv($file, array($res->from_user, $res->to_user, $res->message, $res->date_added));

}

fclose($file);


return response()->make(Storage::disk('csv')->get('file.csv'), 200, $headers);

此返回将在下载后立即删除文件:


return response()->download(Storage::disk('csv')->path('file.csv'))

->deleteFileAfterSend(true);

什么会更安全?更好的方法是什么?我目前倾向于使用存储的第二种方法。


心有法竹
浏览 258回答 3
3回答

芜湖不芜

选项1原因:您没有保留文件,因此保留到磁盘的用途有限数据量很小,所以下载失败的可能性很小,如果发生,重新创建输出的处理时间最短(我假设这是一个快速的 SQL 查询?)将文件保存在存储中为文件复制创造了机会,您将来可能设置的增量备份或 rsync 可以在敏感文件被删除之前复制它们......从文件系统中删除文件并不一定会使数据不可恢复如果您正在处理数十/数百 MB 的文件,我的想法会有所不同......

拉风的咖菲猫

让我们考虑所有选项,选项 1是一个很好的解决方案,因为您没有存储文件。它会比其他人更安全。但是在高流量时超时可能是一个问题。选项 2也是删除的好解决方案。但是您需要创建具有唯一名称的文件,以便您可以使用并行下载。选项 3类似于选项 2,但如果您使用的是 laravel,请不要使用它。(想想2个人同时下载)在此解释之后,如果您使用的是一台服务器,您需要处理选项 1 以使其更安全。但是,如果您使用的是微服务,则需要处理选项 2。我可以再建议一件事来确保它的安全。创建一个唯一的散列 URL。例如,使用时间戳并将其与 laravel 哈希并在 URL 之前检查它们。所以人们不能从下载历史中再次下载。https://example.com/download?hash={crypt(timestamp+1min)}如果 1 分钟内未下载,则 URL 将过期。

明月笑刀无情

我认为回复取决于当前架构和要下载的文件大小(1) 第一种方法适用于以下情况:如果文件很小(小于 10 Mb)谢谢@tanerkay你有简单的架构(例如1台服务器)原因:没有下载失败——无需重试把事情简单化没有文件 = 没有备份,没有 rsync,也没有其他地方可以窃取它. . .(2) 第二种方法适用于以下情况:如果您的文件很大 (10+ Mb)如果您已经拥有具有多个平衡加载器的微服务架构 - 保持相似性如果您有数百万用户尝试下载 - 如果没有平衡加载器和并行下载,您将无法为他们提供服务原因:第二种方法肯定更具可扩展性,因此在高负载下更稳定,因此更安全。对于繁重的负载,微服务更耗时且更具可扩展性。使用单独的文件存储允许您在将来拥有单独的文件服务器和负载平衡以及队列管理器和单独的专用访问控制。如果内容很重要,通常意味着获取它对用户来说非常重要。但是带有标头的直接输出可能会挂起或出现超时错误等。我认为将文件保存到下载之前是更可靠的交付方法。尽管如此,我还是会考虑到期时间而不是下载事实——下载过程可能会失败,或者文件丢失(确保 1 小时以上的可用性),反之亦然,用户将仅在 1 年后尝试下载它,或者永远不会—— - 为什么要保存这个文件超过 N 天?
随时随地看视频慕课网APP
我要回答