PHP 中的唯一和临时文件名?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/460164/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unique and temporary file names in PHP?
提问by cletus
I need to convert some files to PDF and then attach them to an email. I'm using Pear Mail for the email side of it and that's fine (mostly--still working out some issues) but as part of this I need to create temporary files. Now I could use the tempnam()function but it sounds like it creates a file on the filesystem, which isn't what I want.
我需要将一些文件转换为 PDF,然后将它们附加到电子邮件中。我正在使用 Pear Mail 作为它的电子邮件端,这很好(主要是 - 仍在解决一些问题),但作为其中的一部分,我需要创建临时文件。现在我可以使用tempnam()函数,但听起来它在文件系统上创建了一个文件,这不是我想要的。
I just want a name in the temporary file system (using sys_get_temp_dir()) that won't clash with someone else running the same script of the same user invoking the script more than once.
我只想要临时文件系统中的名称(使用sys_get_temp_dir()),该名称不会与运行同一用户多次调用该脚本的相同脚本的其他人发生冲突。
Suggestions?
建议?
回答by Lusid
I've used uniqid() in the past to generate a unique filename, but not actually create the file.
我过去曾使用 uniqid() 生成唯一的文件名,但实际上并未创建文件。
$filename = uniqid(rand(), true) . '.pdf';
The first parameter can be anything you want, but I used rand() here to make it even a bit more random. Using a set prefix, you could further avoid collisions with other temp files in the system.
第一个参数可以是您想要的任何参数,但我在这里使用了 rand() 使其更加随机。使用设置的前缀,您可以进一步避免与系统中的其他临时文件发生冲突。
$filename = uniqid('MyApp', true) . '.pdf';
From there, you just create the file. If all else fails, put it in a while loop and keep generating it until you get one that works.
从那里,您只需创建文件。如果所有其他方法都失败了,请将其放入一个 while 循环中并继续生成它,直到您找到一个可以工作的循环为止。
while (true) {
$filename = uniqid('MyApp', true) . '.pdf';
if (!file_exists(sys_get_temp_dir() . $filename)) break;
}
回答by Chris Cogdon
Seriously, use tempnam(). Yes, this creates the file, but this is a very intentional security measure designed to prevent another process on your system from "stealing" your filename and causing your process to overwrite files you don't want.
说真的,使用 tempnam()。是的,这会创建文件,但这是一种非常有意的安全措施,旨在防止系统上的另一个进程“窃取”您的文件名并导致您的进程覆盖您不想要的文件。
I.e., consider this sequence:
即,考虑这个序列:
- You generate a random name.
- You check the file system to make sure it doesn't exist. If it does, repeat the previous step.
- Another, evil, process creates a file with the same name as a hard link to a file Mr Evil wants you to accidentally overwrite.
- You open the file, thinking you're creating the file rather than opening an existing one in write mode and you start writing to it.
- You just overwrote something important.
- 您生成一个随机名称。
- 您检查文件系统以确保它不存在。如果是,请重复上一步。
- 另一个邪恶的进程创建了一个文件,该文件与邪恶先生希望您不小心覆盖的文件的硬链接同名。
- 您打开文件,认为您正在创建文件而不是在写入模式下打开现有文件,然后您开始写入文件。
- 你只是覆盖了一些重要的东西。
PHP's tempnam() actually calls the system's mkstemp under the hood (that's for Linux... substitute the "best practice" function for other OSs), which goes through a process like this:
PHP 的 tempnam() 实际上在幕后调用系统的 mkstemp(这是针对 Linux 的……替代其他操作系统的“最佳实践”函数),它经历了这样的过程:
- Pick a filename
- Create the file with restrictive permissions, inside a directory that prevents others from removing files it doesn't own (that's what the sticky-bit does on /var/tmp and /tmp)
- Confirms that the file created still has the restrictive permissions.
- If any of the above fails, try again with a different name.
- Returns the filename created.
- 选择一个文件名
- 在一个目录中创建具有限制性权限的文件,以防止其他人删除它不拥有的文件(这就是粘滞位在 /var/tmp 和 /tmp 上所做的)
- 确认创建的文件仍然具有限制性权限。
- 如果上述任何一项失败,请使用其他名称重试。
- 返回创建的文件名。
Now, you can do allof those things yourself, but why, when "the proper function" does everything that's required to create secure temporary files, and that almost always involves creating an empty file for you.
现在,您可以自己做所有这些事情,但是为什么,当“适当的功能”完成创建安全临时文件所需的一切时,而且几乎总是涉及为您创建一个空文件。
Exceptions:
例外:
- You're creating a temporary file in a directory that only your process can create/delete files in.
- Create a randomly generated temporary directory, which only your process can create/delete files in.
- 您正在目录中创建一个临时文件,只有您的进程可以在其中创建/删除文件。
- 创建一个随机生成的临时目录,只有您的进程可以在其中创建/删除文件。
回答by barfoon
You could use part of the date and time in order to create a unique file name, that way it isn't duplicated when invoked more than once.
您可以使用部分日期和时间来创建唯一的文件名,这样在多次调用时就不会重复。
回答by Michael MacDonald
Consider using an uuid for the filename. Consider the uniqid function. http://php.net/uniqid
考虑使用 uuid 作为文件名。考虑 uniqid 函数。 http://php.net/uniqid
回答by tomloprod
Another alternative based on @Lusidanswer with a failover of max execution time:
另一种基于@Lusid最大执行时间故障转移的答案的替代方案:
//////////// Max exectution time of 10 seconds.
$maxExecTime = time() + 10;
$isUnique = false;
while (time() !== $maxExecTime) {
//////////// Unique file name
$uniqueFileName = uniqid(mt_rand(), true) . '.pdf';
if (!file_exists(sys_get_temp_dir() . $uniqueFileName)){
$isUnique = true;
break;
}
}
if($isUnique){
//////////// Save your file with your unique name
}else{
//////////// Time limit was exceeded without finding a unique name
}
Note:
I prefer to use
mt_randinstead ofrandbecause the first function useMersenne Twister algorithmand it's faster than the second (LCG).
笔记:
我更喜欢使用
mt_rand而不是rand因为第一个函数使用Mersenne Twister algorithm并且它比第二个 (LCG)快。
More info:
更多信息:
回答by J Shubham
Better use Unix timestamp with the user id.
最好将 Unix 时间戳与用户 ID 一起使用。
$filename='file_'.time().'_'.$id.'.jepg';
回答by FDisk
I recomend you to use the PHP function http://www.php.net/tempnam
我建议你使用 PHP 函数 http://www.php.net/tempnam
$file=tempnam('tmpdownload', 'Ergebnis_'.date(Y.m.d).'_').'.pdf';
echo $file;
/var/www/html/tmpdownload/Ergebnis_20071004_Xbn6PY.pdf
<?php
$temp = tmpfile();
fwrite($temp, "writing to tempfile");
fseek($temp, 0);
echo fread($temp, 1024);
fclose($temp); // this removes the file
?>
回答by kurdtpage
My idea is to use a recursive function to see if the filename exists, and if it does, iterate to the next integer:
我的想法是使用递归函数来查看文件名是否存在,如果存在,则迭代到下一个整数:
function check_revision($filename, $rev){
$new_filename = $filename."-".$rev.".csv";
if(file_exists($new_filename)){
$new_filename = check_revision($filename, $rev++);
}
return $new_filename;
}
$revision = 1;
$filename = "whatever";
$filename = check_revision($filename, $revision);
回答by FabianoLothor
Update 2020
2020 年更新
hash_file('md5', $file_pathname)
hash_file('md5', $file_pathname)
This way you will prevent duplications.
这样您就可以防止重复。
回答by Valeri Manijashvili
function gen_filename($dir) {
if (!@is_dir($dir)) {
@mkdir($dir, 0777, true);
}
$filename = uniqid('MyApp.', true).".pdf";
if (@is_file($dir."/".$filename)) {
return $this->gen_filename($dir);
}
return $filename;
}

