PHP中的唯一和临时文件名?

时间:2009-01-20 04:55:03

标签: php

我需要将一些文件转换为PDF,然后将它们附加到电子邮件中。我正在使用Pear Mail作为它的电子邮件方面,这很好(主要是 - 仍在解决一些问题)但作为其中的一部分,我需要创建临时文件。现在我可以使用tempnam()函数,但听起来它在文件系统上创建了一个文件,这不是我想要的。

我只想在临时文件系统中使用一个名称(使用sys_get_temp_dir()),该名称不会与运行同一用户的同一脚本的其他人多次冲突。

建议?

10 个答案:

答案 0 :(得分:138)

我过去曾使用uniqid()来生成唯一的文件名,但实际上并没有创建文件。

$filename = uniqid(rand(), true) . '.pdf';

第一个参数可以是你想要的任何东西,但是我在这里使用了rand()使它更加随机。使用set前缀,可以进一步避免与系统中的其他临时文件冲突。

$filename = uniqid('MyApp', true) . '.pdf';

从那里,您只需创建文件。如果所有其他方法都失败了,那就把它放在while循环中并继续生成它,直到你得到一个有效的方式。

while (true) {
 $filename = uniqid('MyApp', true) . '.pdf';
 if (!file_exists(sys_get_temp_dir() . $filename)) break;
}

答案 1 :(得分:23)

说真的,使用tempnam()。是的,这会创建文件,但这是一个非常有意的安全措施,旨在防止系统上的其他进程“窃取”您的文件名并导致您的进程覆盖您不想要的文件。

即,请考虑以下顺序:

  • 您生成一个随机名称。
  • 检查文件系统以确保它不存在。如果是,请重复上一步。
  • 另一个邪恶的进程创建一个文件,其名称与Evil先生希望您不小心覆盖的文件的硬链接相同。
  • 您打开文件,认为您正在创建文件,而不是在写入模式下打开现有文件并开始写入文件。
  • 你刚刚覆盖了一些重要的东西。

PHP的tempnam()实际上调用了系统的mkstemp(用于Linux ...替换其他操作系统的“最佳实践”功能),这样就完成了这样的过程:

  • 选择文件名
  • 在一个目录中创建具有限制权限的文件,该目录阻止其他人删除它不拥有的文件(这是粘性位在/ var / tmp和/ tmp上执行的操作)
  • 确认创建的文件仍具有限制性权限。
  • 如果上述任何一项失败,请使用其他名称重试。
  • 返回创建的文件名。

现在,您可以自己所有这些事情,但为什么,当“正确的功能”执行创建安全临时文件所需的所有内容时,为什么,这几乎总是涉及创建一个空文件你。

例外:

  • 您正在目录中创建临时文件,只有您的进程可以创建/删除文件。
  • 创建一个随机生成的临时目录,只有您的进程可以创建/删除文件。

答案 2 :(得分:3)

您可以使用部分日期和时间来创建唯一的文件名,这样在多次调用时不会重复。

答案 3 :(得分:2)

考虑使用uuid作为文件名。考虑uniqid函数。 http://php.net/uniqid

答案 4 :(得分:1)

另一种基于@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
}
  

注意:

     

我更喜欢使用mt_rand而不是rand,因为第一个函数使用Mersenne Twister algorithm并且比第二个函数(LCG更快)。

更多信息:

答案 5 :(得分:0)

我建议你使用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

或者 http://www.php.net/tmpfile

<?php
$temp = tmpfile();
fwrite($temp, "writing to tempfile");
fseek($temp, 0);
echo fread($temp, 1024);
fclose($temp); // this removes the file
?>

答案 6 :(得分:0)

最好使用带有用户ID的Unix时间戳。

$filename='file_'.time().'_'.$id.'.jepg';

答案 7 :(得分:0)

我的想法是使用递归函数来查看文件名是否存在,如果存在,则迭代到下一个整数:

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);

答案 8 :(得分:0)

更新2020

hash_file('md5', $file_pathname)

这样,您可以防止重复。

答案 9 :(得分:-1)

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;
}