对于2个并发执行的脚本,uniqid()是否可以相同?

时间:2017-12-07 18:36:48

标签: php

我使用以下代码在服务器上保存文件:

<?php
$uuid = uniqid();
$uploaddir = getcwd();
$uploaddir = $uploaddir ."/files/";
$uploadfile = $uploaddir.$uuid. basename($_FILES['image_file']['name']);
$relativePath = "files/".$uuid. basename($_FILES['image_file']['name']);

if (move_uploaded_file($_FILES['image_file']['tmp_name'], $uploadfile)) {
  echo $relativePath;
} else {
   echo "Error";
}
?>

我很困惑PHP如何处理同时性。

让我们举个例子。 2个用户在同一时间上传文件(同名),因此PHP应该同时执行。

我知道有数百个PHP脚本可以同时运行,但我不知道它们是否可以这样的方式,从当前时间计算的uniqid()对于两个脚本执行都是相同的。如果uuid()可以相同,我应该为文件名选择什么前缀?

1 个答案:

答案 0 :(得分:0)

来自manual

  

此功能不保证返回值的唯一性。由于大多数系统通过NTP等调整系统时钟,因此系统时间会不断变化。因此,该函数可能不返回进程/线程的唯一ID。使用more_entropy来增加唯一性的可能性。

如果,不知何故,这发生在系统中相同的记录微秒,它将是相同的。

我的首选方法是在这种字符串中种下你知道独特的东西。例如,您可以将主键和uniqid一起散列。如果您不担心公开主键,可以使用md5之类的简单内容,甚至可以使用ID作为前缀。如果您使用md5,则生成的字符串将长于uniqid

另一种选择是生成uniqid并在写入文件之前将其插入具有唯一约束的关系数据库中。如果插入因唯一约束违规而失败,则可以将其嵌入循环中直到成功。

<?php

/**
 * Generates a unique value to be used as a filename.
 * @return string
 */
function getUniqueId(): string
{
    $stmt = $pdo->prepare('INSERT INTO unique_filenames (value) VALUES (?)');
    // thanks to random_int, this should only need to happen once.
    // limit to 10 tries in order to avoid an infinite loop.
    for ($i=0;$i<10;$i++) {
        $unique = uniqid(random_int(1000,9999), true); // second value is more entropy
        try {
            $stmt->execute([$unique]);
            return $unique;
        } catch (\PDOException) {
            error_log('file collision. trying again.');
        }
    }

    throw new MyCustomException('Somehow failed to generate a unique ID');
}