Уникальные и временные имена файлов в PHP?
Мне нужно конвертировать некоторые файлы в PDF, а затем присоединить их к электронной почте. Я использую Pear Mail для электронной почты, и это прекрасно (в основном - все еще разрабатываю некоторые проблемы), но в качестве части этого мне нужно создать временные файлы. Теперь я мог бы использовать функцию tempnam(), но похоже, что она создает файл в файловой системе, чего я не хочу.
Мне просто нужно указать имя во временной файловой системе (используя sys_get_temp_dir()), который не будет конфликтовать с кем-то, w370 > того же пользователя, вызывающего script более одного раза.
Предложения?
Ответы
Ответ 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;
}