我使用以下代码在服务器上保存文件:
<?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()可以相同,我应该为文件名选择什么前缀?
答案 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');
}