Уникальные и временные имена файлов в PHP? - PullRequest
51 голосов
/ 20 января 2009

Мне нужно конвертировать некоторые файлы в PDF, а затем прикрепить их к электронному письму. Я использую Pear Mail для электронной почты, и это нормально (в основном - все еще решаются некоторые проблемы), но как часть этого мне нужно создать временные файлы. Теперь я могу использовать функцию tempnam () , но похоже, что она создает файл в файловой системе, а это не то, что мне нужно.

Мне просто нужно имя во временной файловой системе (используя sys_get_temp_dir () ), которое не будет конфликтовать с кем-то, кто запускает тот же сценарий того же пользователя, вызывая сценарий несколько раз. *

Предложения

Ответы [ 9 ]

139 голосов
/ 20 января 2009

В прошлом я использовал 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;
}
23 голосов
/ 19 февраля 2016

Серьезно, используйте tempnam (). Да, это создает файл, но это очень преднамеренная мера безопасности, предназначенная для предотвращения "кражи" вашего имени другим процессом в вашей системе и побуждения вашего процесса перезаписывать файлы, которые вам не нужны.

Т.е., рассмотрим следующую последовательность:

  • Вы генерируете случайное имя.
  • Вы проверяете файловую систему, чтобы убедиться, что она не существует. Если это так, повторите предыдущий шаг.
  • Другой, злой, процесс создает файл с тем же именем, что и жесткая ссылка на файл, который мистер Зло хочет, чтобы вы случайно перезаписали.
  • Вы открываете файл, думая, что вы создаете файл, а не открываете существующий в режиме записи, и начинаете писать в него.
  • Вы просто переписали что-то важное.

PHP tempnam () фактически вызывает системный mkstemp под капотом (это для Linux ... замените функцию "передового опыта" для других ОС), которая проходит такой процесс:

  • Выберите имя файла
  • Создайте файл с ограниченными правами внутри каталога, который не позволяет другим удалять файлы, которые ему не принадлежат (это то, что делает sticky-бит в / var / tmp и / tmp)
  • Подтверждает, что созданный файл все еще имеет ограничительные разрешения.
  • Если что-то из вышеперечисленного не помогло, попробуйте еще раз с другим именем.
  • Возвращает созданное имя файла.

Теперь вы можете сделать все из этих вещей самостоятельно, но почему, когда «правильная функция» делает все, что требуется для создания безопасных временных файлов, и это почти всегда включает создание пустого файла для вас .

Исключения:

  • Вы создаете временный файл в каталоге, в котором только ваш процесс может создавать / удалять файлы.
  • Создайте случайно сгенерированный временный каталог , в котором только ваш процесс может создавать / удалять файлы.
3 голосов
/ 20 января 2009

Можно использовать часть даты и времени для создания уникального имени файла, чтобы оно не дублировалось при вызове более одного раза.

2 голосов
/ 20 января 2009

Подумайте об использовании uuid для имени файла. Рассмотрим уникальную функцию. http://php.net/uniqid

1 голос
/ 11 января 2017

Другая альтернатива, основанная на @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 голосов
/ 02 августа 2017

Моя идея состоит в том, чтобы использовать рекурсивную функцию, чтобы увидеть, существует ли имя файла, и, если это так, перейдите к следующему целому числу:

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);
0 голосов
/ 29 октября 2016

Лучше использовать метку времени Unix с идентификатором пользователя.

$filename='file_'.time().'_'.$id.'.jepg';
0 голосов
/ 08 января 2015
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;
}
0 голосов
/ 11 марта 2011

Я рекомендую вам использовать функцию 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
?>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...