我建议使用以下数据库结构:
文件表至少包含以下内容:
IDFile列是自增列/主键。
UserID是可空外键。
对于FK_File_User,我建议:
ON UPDATE NO ACTION
ON DELETE SET NULL
另外,File
表可能会添加其他列:
- 实际上传日期和时间
- 实际 MIME 类型
- 实际存储位置(对于分布式存储系统)
- 下载计数(另一个表可能是更好的解决方案)
等等...
一些好处:
- 您不需要计算文件大小、哈希、扩展名或任何文件元数据,因为您可以通过一个数据库操作获得它。
- 您可以通过单个
SELECT ... GROUP BY ... WITH ROLLUP
语句为 File
表中每个用户获取文件数量/使用空间/任何您编写的统计信息,并且这比分析实际文件要快,因为实际文件可能分布在多个存储设备上。
- 您可以为不同的用户应用文件访问权限。这将不会显着改变表结构数据库。
我不认为原始文件名需要存储,因为有两个原因:
- 文件可能具有名称,该名称不受服务器操作系统文件系统正确支持,例如 Cyrillic。
- 两个不同的文件可能具有完全相同的名称,因此其中一个可能被另一个覆盖。
因此,有一个解决方案:
1) 在上传到 File
表的 INSERT
中将文件重命名为 IDFile
。这是安全的,没有重复。
2) 在需要/下载文件时恢复文件名,例如:
list($name, $ext, $size, $md5) = $result->fetch_row();
$result->free();
header('Content-Length: ' . $size);
header('Content-MD5: ' . $md5);
header('Accept-Ranges: bytes');
header('Connection: close');
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename="' . $name . '.' . $ext . '"');
3)实际文件可以存储在单个目录中(因为 IDFile
是安全的),也可以存储在以 IDUser
命名的子目录中,这取决于具体情况。
4)由于 IDFile
是直接序列,如果某些文件丢失了,您可以通过评估实际文件名序列中缺失的段来获取它们的数据库元数据。然后,您可以执行“通知所有者”、“删除文件元数据”或这两个操作。
我反对将大型实际文件作为二进制内容存储在 DBMS 中的想法。
DBMS 是关于数据和分析的,它不是一个文件系统,如果我的看法有用的话,就不应该以这种方式使用它。
/home/user/files/1/image.png
,然后我会根据文件名创建哈希并插入ID,然后将其保存到数据库中。检索只需使用PHP即可控制下载和下载计数器。任何具有相同文件名的内容都没有关系。并且一定要研究S3。 - Dave