2009-01-20 109 views
46

我需要將一些文件轉換爲PDF,然後將它們附加到電子郵件。我使用Pear Mail作爲它的電子郵件端,這很好(主要 - 仍然解決一些問題),但作爲這一部分,我需要創建臨時文件。現在我可以使用tempnam()函數,但它聽起來像在文件系統上創建了一個文件,這不是我想要的。PHP中的唯一和臨時文件名?

我只是想在臨時文件系統中使用一個名稱(使用sys_get_temp_dir()),該名稱不會與運行同一用戶的同一腳本的其他人重複多次調用該腳本。

對此提出建議?

回答

122

我以前用uniqid()生成一個唯一的文件名,但實際上並沒有創建文件。

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

第一個參數可以是任何你想要的,但我在這裏使用rand()使它更加隨機。使用設置的前綴,可以進一步避免與系統中其他臨時文件的衝突。

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

從那裏,你只是創建文件。如果一切都失敗了,把它放在一個while循環中,並繼續生成它,直到你得到一個工作。

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

+1 while循環! – RobertPitt 2011-03-10 21:05:33

+4

我喜歡在uniquid上使用第一個參數的隨機數,但是我使用mt_rand()來代替,因爲它的速度。這對於使用while循環的地方會有幫助,並且有很多文件。 – 2011-05-29 16:55:12

+0

我不知道在那裏添加一個rand()是否會使得它有更多*隨機 - 可能是uniqid和rand()都被系統時間所接種。 – 2013-03-18 23:16:29

3

您可以使用日期和時間的一部分來創建唯一的文件名,這樣在多次調用時不會重複。

-1

我建議你使用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 
?> 
-1
function gen_filename($dir) { 
    if ([email protected]_dir($dir)) { 
     @mkdir($dir, 0777, true); 
    } 
    $filename = uniqid('MyApp.', true).".pdf"; 
    if (@is_file($dir."/".$filename)) { 
     return $this->gen_filename($dir); 
    } 
    return $filename; 
} 
11

嚴重的是,使用的tempnam()。是的,這會創建文件,但這是一種非常有意的安全措施,旨在防止系統上的其他進程「竊取」文件名並導致進程覆蓋不需要的文件。

即,考慮這個序列:

  • 您生成一個隨機的名字。
  • 您檢查文件系統以確保它不存在。如果有,請重複上一步。
  • 另一個邪惡的過程會創建一個與Evil希望您意外覆蓋的文件的硬鏈接具有相同名稱的文件。
  • 您打開文件,認爲您正在創建文件,而不是在寫入模式下打開現有文件,然後開始寫入文件。
  • 你剛剛重寫了一些重要的東西。

PHP的tempnam()實際上在引擎蓋下調用系統的mkstemp(這是Linux的... ...替代其他操作系統的「最佳實踐」功能),它經過這樣一個過程:

  • 選擇一個文件名
  • 創建具有限制性權限的文件,防止他人刪除它doesn文件的目錄內't擁有(這就是/ var/tmp和/ tmp上的粘性位)
  • 確認創建的文件仍具有限制性權限。
  • 如果上述任何一項失敗,請以不同的名稱再次嘗試。
  • 返回創建的文件名。現在

,你可以做所有的那些東西的事情,但爲什麼當「適當功能」確實的需要的,以創建安全的臨時文件,而且幾乎總是涉及爲您創造一個空文件的一切。

例外:

  • 你正在創建中,只有你的進程可以創建/刪除中的文件的目錄的臨時文件
  • 創建一個隨機生成的臨時目錄,只有你的過程創建/刪除文件英寸
0

更好,如果您使用unix時間戳與用戶ID。

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

2

基於@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)快。


更多信息:

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