随机文件名生成功能需要几分钟才能生成唯一名称

时间:2014-07-24 17:53:04

标签: php random filenames uniqueidentifier

我需要为上传的文件生成唯一的文件名。我将名称存储在数据库中,并在生成文件名时检查以确保它是唯一的。我知道这里有很多关于这个问题的问题,但是我试图理解的是为什么我的脚本不起作用。

她的代码是获取文件名并检查它是否唯一:

do {
    $newName  = generateRandomString(10, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');

    $stmt = $this->db->prepare('SELECT id FROM images WHERE file_name = :newName');
    makeQuery($stmt, array(':newName' => $newName));
    $row = $stmt->fetch(\PDO::FETCH_ASSOC);
} while(!empty($row));

generateRandomString()的位置:

function generateRandomString($length, $characters) {
    $randomString = '';

    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, strlen($characters) - 1)];
    }

    return $randomString;
}

现在,当我在我的数据库中运行大约30,000个文件名时,需要几秒钟到几个分钟来返回文件名。

如果我在文件名(0-9a-zA-Z)中使用的字符数量和长度都是10,那么应该有大量潜在的文件名(如果我计算它的话,大约需要1070亿)对)。看起来根本不应该有任何碰撞,最不重要的是我得到的数字(我分析的一个XDebug配置文件快照说generateRandomString()跑过 100,000 回来之前!)。

为什么这不起作用,我该怎么做才能解决它?

编辑:哎呀,我误解了xdebug数据。它没有进行100,000次函数调用,花了123,502毫秒(所以时间,而不是函数调用)。

2 个答案:

答案 0 :(得分:2)

此代码存在许多问题:

  • SELECT,然后INSERT容易出现竞争条件(在两个语句之间,另一个进程插入了相同的ID)。干净的方法是乐观地插入一行,并重复重复键错误,更好地使用确定性的独特功能。
  • 您为每个循环准备一个新语句。干净的方法是准备一次语句,然后用不同的参数重复执行它。这就是为什么它们被称为预备语句
  • 您的实现使用PHP的rand()函数,它根据PHP版本和操作系统产生完全不同的随机性。使用mt_rand();

我建议您在数据库中创建标识符:请参阅我的answer to another SO question

答案 1 :(得分:0)

我想我找到了解决方案:

http://kvz.io/blog/2009/06/10/create-short-ids-with-php-like-youtube-or-tinyurl/

此代码生成的所有ID都是唯一的