Подтвердить что ты не робот

Уникальные и временные имена файлов в PHP?

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

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

Предложения?

4b9b3361

Ответ 1

Я использовал uniqid() в прошлом для создания уникального имени файла, но фактически не создавал файл.

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

Первый параметр может быть любым, что вы хотите, но я использовал rand() здесь, чтобы сделать его еще более случайным. Используя префикс набора, вы можете избежать столкновения с другими файлами temp в системе.

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

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

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

Ответ 2

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

I.e., рассмотрим эту последовательность:

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

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

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

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

Исключения:

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

Ответ 3

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

Ответ 4

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

Ответ 5

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


Дополнительная информация:

Ответ 6

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

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

Ответ 7

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

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

Я рекомендую вам использовать функцию 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
?>

Ответ 9

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