如何确保上传到服务器的图像的唯一文件名?

时间:2014-02-25 01:28:01

标签: php

我正在创建一个允许用户将图像上传到服务器的Web应用程序。

当用户上传图片时,如何防止重复的图像文件名?

如何将文件名更改为与之前任何图像的名称(或可能上传的下一张图像)无关的唯一名称?

编辑:

如果我将主键自动增量用作每个图像的图像文件名?这会有用吗?

3 个答案:

答案 0 :(得分:4)

我之前有already answered这样的问题。我更新了我的代码,为生成的id添加了更多的随机性(熵)。

此类生成伪唯一,非顺序,非数字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()需要返回完全相同的随机值相同的顺序...连续七次。最重要的是它是随机的。

**编辑2 **

您可能也对[{3}}实施感兴趣。

**编辑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?

在这里:http://php.net/uniqid