我正在创建一个允许用户将图像上传到服务器的Web应用程序。
当用户上传图片时,如何防止重复的图像文件名?
如何将文件名更改为与之前任何图像的名称(或可能上传的下一张图像)无关的唯一名称?
编辑:
如果我将主键自动增量用作每个图像的图像文件名?这会有用吗?
答案 0 :(得分:4)
此类生成伪唯一,非顺序,非数字ID。
class IdGenerator {
static private function _nextChar() {
return base_convert(mt_rand(0, 35), 10, 36);
}
static public function generate() {
$parts = explode('.', uniqid('', true));
$id = str_pad(base_convert($parts[0], 16, 2), 56, mt_rand(0, 1), STR_PAD_LEFT)
. str_pad(base_convert($parts[1], 10, 2), 32, mt_rand(0, 1), STR_PAD_LEFT);
$id = str_pad($id, strlen($id) + (8 - (strlen($id) % 8)), mt_rand(0, 1), STR_PAD_BOTH);
$chunks = str_split($id, 8);
$id = array();
foreach ($chunks as $key => $chunk) {
if ($key & 1) { // odd
array_unshift($id, $chunk);
} else { // even
array_push($id, $chunk);
}
}
// add random seeds
$prefix = str_pad(base_convert(mt_rand(), 10, 36), 6, self::_nextChar(), STR_PAD_BOTH);
$id = str_pad(base_convert(implode($id), 2, 36), 19, self::_nextChar(), STR_PAD_BOTH);
$suffix = str_pad(base_convert(mt_rand(), 10, 36), 6, self::_nextChar(), STR_PAD_BOTH);
return $prefix . self::_nextChar() . $id . $suffix;
}
}
如果您执行此脚本
header('Content-type: text/plain; charset=utf-8');
for ($i=0; $i<10; $i++) {
$uid = IdGenerator::generate();
echo $uid . " = " . strlen($uid) . "\n";
}
你会得到这样的东西:
x0i8eea3c8kw4lgudmoss4c4w03db6wl = 32
byqrfgc6hilr9d1ot4wow8gw4syugtvz = 32
ta075al22zp3v6awtlw4kgkk446mjbiv = 32
hqqa90p27e9desx99q8skokcc46fujx4 = 32
uqc000q7g20l1k9zlwko80gsow5e59e7 = 32
gxx2r5d5oa0p8iykvc4ckgc4kc0teekv = 32
ayysoos5ltfua3d0m80ccocc0kcfhqyb = 32
dtj31vi4tzmh6lhk1iccc0os4cgsze1e = 32
fvn41hh2gnk6lbrq4w0wwgko8k5ihda8 = 32
oxamsba3qh0ro6xehkw8cg400s10tiyq = 32
那么,为什么这一切呢?为什么不使用uniqid()
?因为uniqid()
是顺序的并且是可预测的。因为你需要添加更多的熵。该类不仅使用uniqid()
“更多熵”参数,还使用mt_rand()
来填充生成的值。这里提供的类也将始终生成一个32字节(256位)的字符串。
这个功能是多么随机?要获得重复的ID,需要在完全同时调用uniqid()
,并且mt_rand()
需要返回完全相同的随机值相同的顺序...连续七次。最重要的是它是随机的。
您可能也对[{3}}实施感兴趣。
使用主键(PK)作为唯一文件名的问题在于它是可预测的。如果您打算直接从URI路由提供这些文件,则生成的非顺序值更安全。如果您打算以其他方式提供这些文件,那么无论如何都必须为这些文件分配一些唯一的密钥......并且由于完全相同的原因,此密钥不能是顺序的。因此,无论用例如何,将非顺序唯一键作为文件名都是个好主意。
答案 1 :(得分:0)
保证唯一文件名的最简单方法是使用为每个新图像增加的简单序列。
如果您使用像MySQL
这样的数据库来存储图像的其他信息,您可以使用自动分配的主键列ID AUTO_INCREMENT
,或者您也可以只存储当前序列值在一个简单的文本文件中。
请注意,使用文件存储当前值的选项很危险,因为只需访问它,两个并发文件上传就可以生成相同的文件名。您可以使用文件锁(请参阅flock
的文档)来规避这一点,但这可能效率低下。
使用散列函数不能保证产生唯一ID,因为两个不同的输入可以生成相同的输出(通常一些输出概率很低)。此外,时间戳可能只是不准确,因此如果在很短的时间内上传两个文件,则会产生相同的文件名。
答案 2 :(得分:-1)
您可以使用当前时间戳*的随机数*,例如
$date = date('Y-m-d H:i:s');
$filename = md5(uniqid($date, true) * rand()) . ".png";
另请看这里:PHP: How to generate a random, unique, alphanumeric string?