2009-01-20 15 views
46

Potrzebuję przekonwertować niektóre pliki do formatu PDF, a następnie dołączyć je do wiadomości e-mail. Używam Pear Mail dla strony e-mailowej i jest to w porządku (głównie - wciąż pracuję nad niektórymi problemami), ale jako część tego potrzebuję utworzyć pliki tymczasowe. Teraz mógłbym użyć funkcji tempnam(), ale wygląda na to, że tworzy plik w systemie plików, co nie jest tym, czego potrzebuję.Unikalne i tymczasowe nazwy plików w PHP?

Po prostu chcę nazwę w tymczasowym systemie plików (przy użyciu sys_get_temp_dir()), która nie będzie kolidować z kimś, kto uruchamia ten sam skrypt tego samego użytkownika wywołującego skrypt więcej niż raz.

Sugestie?

Odpowiedz

122

Używałem uniqid() w przeszłości do generowania unikatowej nazwy pliku, ale w rzeczywistości nie tworzyłem tego pliku.

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

Pierwszy parametr może być dowolnym parametrem, ale użyłem tutaj rand(), aby uczynić go jeszcze bardziej losowym. Za pomocą ustalonego prefiksu można dodatkowo uniknąć kolizji z innymi plikami tymczasowymi w systemie.

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

Stamtąd wystarczy utworzyć plik. Jeśli wszystko inne zawiedzie, włóż to w pętlę i kontynuuj generowanie, dopóki nie otrzymasz takiego, który działa.

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

+1 za pętlę while! – RobertPitt

+4

Podoba mi się użycie liczby losowej dla pierwszego parametru na uniquid, jednak zamiast tego używam mt_rand() z powodu jego szybkości. będzie to pomocne w miejscach takich, w których używana jest pętla while i jest wiele plików. –

+0

Nie wiem, czy dodanie rand() w nim będzie koniecznie uczynić go dowolnym * more * random - szanse są takie, że zarówno uniqid, jak i rand() są rozstawiane przez czas systemowy. –

3

Możesz użyć części daty i godziny, aby utworzyć niepowtarzalną nazwę pliku, w ten sposób nie zostanie ona powielona, ​​gdy zostanie wywołana więcej niż raz.

+9

Jeśli nie jesteś NAPRAWDĘ zajęty. –

-1

Polecam korzystanie z funkcji 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 

Albo 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 
?> 
+0

To nie zadziała dobrze, ponieważ na przykład tempnam będzie działać. wykryj, że plik AbCdEf nie istnieje i dlatego zwróć tę nazwę. Ale dodajesz .pdf i może już istnieć plik AbCdEf.pdf (którego tempnam nie mógł wykryć) – k3a

+0

To jest złe. Funkcja tempnam() faktycznie tworzy plik, a OP stwierdził, że jest to powód, dla którego nie jest używany tempnam. Twoje rozwiązanie nie powiedzie się, ponieważ utworzony plik nie będzie plikiem, którego szukasz (plik xyz został utworzony, szukasz pliku xyz.pdf). – crafter

-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

Poważnie, stosowanie tempnam(). Tak, to tworzy plik, ale jest to bardzo celowy środek bezpieczeństwa zaprojektowany w celu uniemożliwienia innemu procesowi w twoim systemie "kradzieży" twojej nazwy pliku i spowodowaniu, że twój proces nadpisuje pliki, których nie chcesz.

Tj, należy rozważyć tę sekwencję:

  • wygenerować losową nazwę.
  • Sprawdzasz system plików, aby upewnić się, że nie istnieje. Jeśli tak, powtórz poprzedni krok.
  • Kolejny, zły proces tworzy plik o tej samej nazwie, co twardy link do pliku Mr Evil chce, abyś przypadkowo nadpisał.
  • Otwierasz plik, myśląc, że tworzysz plik zamiast otwierania istniejącego w trybie zapisu i zaczynasz do niego pisać.
  • Po prostu nadpisałeś coś ważnego.

PHP tempnam() faktycznie wywołuje mkstemp systemu pod maską (to dla Linuksa ...zastąpić funkcję „najlepszych praktyk” dla innych systemów operacyjnych), która przechodzi przez proces jak ten:

  • Wybierz nazwę pliku
  • Utwórz plik z ograniczonymi uprawnieniami, wewnątrz katalogu, który uniemożliwia innym użytkownikom usuwanie plików nie robi własna (to właśnie robi stick-bit na/var/tmp i/tmp)
  • Potwierdza, że ​​utworzony plik nadal ma restrykcyjne uprawnienia.
  • Jeśli którakolwiek z powyższych czynności nie powiedzie się, spróbuj ponownie pod inną nazwą.
  • Powoduje powrót do utworzonej nazwy pliku.

Teraz można zrobić wszystkie z tych rzeczy samemu, ale dlaczego, kiedy „właściwa funkcja” robi wszystko, co niezbędne do stworzenia bezpiecznych plików tymczasowych, a prawie zawsze wymaga utworzenia pusty plik dla ciebie.

wyjątkami.

  • Ty tworzysz plik tymczasowy w katalogu, że tylko proces może tworzyć/usuwać pliki w
  • Tworzenie losowo generowany tymczasowy katalogu, które tylko Twój proces może tworzyć/usuwać pliki.
0

Lepsze, jeśli używasz znacznika czasowego unix z identyfikatorem użytkownika.

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

2

Inną alternatywą na podstawie @Lusid odpowiedź z failover max czas wykonywania:

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

Uwaga:

wolę używać mt_rand zamiast rand, ponieważ pierwsza funkcja korzysta z Mersenne Twister algorithm i jest szybsza niż druga (LCG).


Więcej informacji:

0

Mój pomysł jest użycie funkcji rekurencyjnej, aby zobaczyć jeśli nazwa pliku istnieje, a jeśli tak, to iteruj do następnej liczby całkowitej:

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); 
Powiązane problemy