我的Linux服务器上有成千上万的用户上传了数千张图片,这些用户由1and1.com托管(我相信他们使用的是CentOS,但我不确定该版本)。这是一个与语言无关的问题,但是,供您参考,我使用的是PHP。
我的第一个想法是将它们全部转储到同一目录中,但是,我记得不久之前,在目录中可以删除多少文件或目录是有限制的。
我的第二个想法是根据用户的电子邮件地址对目录中的文件进行分区(因为这是我用于用户名的任何方式),但我不希望遇到目录中目录的限制。 ...
无论如何,对于来自user@domain.com的图片,我打算这样做:
/images/domain.com/user/images...
这样做是否明智,如果成千上万的用户说“gmail”,或许我甚至可以更深入,如此
/images/domain.com/[first letter of user name]/user/images...
所以对于mike@gmail.com来说就是......
/images/domain.com/m/mike/images...
这是一种不好的方法吗?其他人在做什么?我也不想遇到太多目录的问题......
相关:
答案 0 :(得分:27)
我会做以下事情:
使用散列还可以合并多次上传的相同图像。
答案 1 :(得分:4)
扩展Joe Beda的方法:
如果您关心按用户分组或查找文件,原始文件名,上传日期,拍照日期(EXIF)等,请将此元数据存储在数据库中并使用相应的查询来挑选相应的文件
使用数据库主键 - 无论是文件哈希值还是自动增量号 - 在一组固定目录中查找文件(或者,每个目录使用固定的最大文件数N,并在填满时转到下一个,例如 k 照片应该存储在{somepath}/aaaaaa/bbbb.jpg
,其中aaaaaa = floor(k / N),格式为十进制或十六进制,bbbb = mod(k, N),格式化为十进制或十六进制。如果你的层次结构过于扁平,请使用类似{somepath}/aa/bb/cc/dd/ee.jpg
)的内容
不要直接将目录结构公开给用户。如果他们使用Web浏览器通过HTTP访问您的服务器,请为他们提供类似www.myserver.com/images/{primary key}的URL,并在Content-Type标头中编码正确的文件类型。
答案 2 :(得分:3)
我用于其他要求但可以满足您需求的是使用简单的约定。
递增1并获取新数字的长度,然后使用此数字作为前缀。
例如:
假设'a'是用最后一个id设置的var。
a = 564;
++a;
prefix = length(a);
id = prefix + a; // 3565
然后,您可以使用此约定使用目录的时间戳:
20092305 (yyyymmdd)
然后你可以像这样爆炸你的道路:
2009/23/05/3565.jpg
(或更多)
这很有趣,因为您可以按日期和数字同时保存排序顺序(有时很有用) 而且你仍然可以在更多目录中分解你的路径
答案 3 :(得分:3)
以下是我在这种情况下写的两个函数。他们已经在拥有数千名成员的网站上使用了一年多,每个成员都有很多文件。
本质上,我们的想法是使用每个成员的唯一数据库ID的最后数字来计算目录结构,并为每个人提供唯一的目录。使用最后的数字而不是第一个数字可确保更均匀的目录传播。每个成员的单独目录意味着维护任务要简单得多,而且你可以看到人们的东西在哪里(如在视觉上)。
// checks for member-directories & creates them if required
function member_dirs($user_id) {
$user_id = sanitize_var($user_id);
$last_pos = strlen($user_id);
$dir_1_pos = $last_pos - 1;
$dir_2_pos = $last_pos - 2;
$dir_3_pos = $last_pos - 3;
$dir_1 = substr($user_id, $dir_1_pos, $last_pos);
$dir_2 = substr($user_id, $dir_2_pos, $last_pos);
$dir_3 = substr($user_id, $dir_3_pos, $last_pos);
$user_dir[0] = $GLOBALS['site_path'] . "files/members/" . $dir_1 . "/";
$user_dir[1] = $user_dir[0] . $dir_2 . "/";
$user_dir[2] = $user_dir[1] . $dir_3 . "/";
$user_dir[3] = $user_dir[2] . $user_id . "/";
$user_dir[4] = $user_dir[3] . "sml/";
$user_dir[5] = $user_dir[3] . "lrg/";
foreach ($user_dir as $this_dir) {
if (!is_dir($this_dir)) { // directory doesn't exist
if (!mkdir($this_dir, 0777)) { // attempt to make it with read, write, execute permissions
return false; // bug out if it can't be created
}
}
}
// if we've got to here all directories exist or have been created so all good
return true;
}
// accompanying function to above
function make_path_from_id($user_id) {
$user_id = sanitize_var($user_id);
$last_pos = strlen($user_id);
$dir_1_pos = $last_pos - 1;
$dir_2_pos = $last_pos - 2;
$dir_3_pos = $last_pos - 3;
$dir_1 = substr($user_id, $dir_1_pos, $last_pos);
$dir_2 = substr($user_id, $dir_2_pos, $last_pos);
$dir_3 = substr($user_id, $dir_3_pos, $last_pos);
$user_path = "files/members/" . $dir_1 . "/" . $dir_2 . "/" . $dir_3 . "/" . $user_id . "/";
return $user_path;
}
sanitize_var()是擦洗输入和支持的支持功能。确保它的数字,$ GLOBALS ['site_path']是服务器的绝对路径。希望他们不会自我解释。
答案 4 :(得分:2)
Joe Beda的答案几乎是完美的,但是请注意MD5已被证明可以在笔记本电脑上2小时内在iirc中碰撞?
也就是说,如果您实际上将以所描述的方式使用文件的MD5哈希,您的服务将变得容易受到攻击。攻击怎么样?
有人说:我们不要覆盖它。然后,如果可以预测有人会上传某些内容(例如,网页上的热门图片可能会上传),则可以首先获取它的“哈希位置”。用户在上传小猫的照片时会很高兴,他会发现它实际上显示为(在这里使用你的想象力)。 我说:使用SHA1,因为它已被证明在127年内被一个10.000计算机集群在iirc中被黑客攻击了吗?
答案 5 :(得分:0)
可能会迟到这个游戏。但是一个解决方案(如果它适合您的用例)可能是文件名哈希。这是一种使用文件名创建易于重现的文件路径的方法,同时还可以创建分布均匀的目录结构。例如,您可以使用文件名的哈希码的字节作为其路径:
String fileName = "cat.gif";
int hash = fileName.hashCode();
int mask = 255;
int firstDir = hash & mask;
int secondDir = (hash >> 8) & mask;
这将导致路径为:
/172/029/cat.gif
然后,您可以通过重现算法在目录结构中找到cat.gif
。
使用HEX作为目录名称就像转换int
值一样简单:
String path = new StringBuilder(File.separator)
.append(String.format("%02x", firstDir))
.append(File.separator)
.append(String.format("%02x", secondDir)
.toString();
导致:
/AC/1D/cat.gif
几年前我写了一篇关于此的文章,最近将其转移到了中级。它有一些细节和一些示例代码:File Name Hashing: Creating a Hashed Directory Structure。希望这有帮助!