Генерация уникального имени файла на PHP

       PHP      php    шпаргалки    полезности      115    
PHP: Генерация уникального имени файла

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

Самый простой вариант – использовать встроенную в PHP функцию uniqid():

// Строка длиной в 13 символов
$fileName = uniqid();

// Используем префикс
// Например: php_5dcb4d75361c9
$fileName = uniqid('php_');

// Строка длиной в 23 символа
// Например: php_5dcb4eb2368202.10751068
$fileName = uniqid('php_', true);

Более сложный (более близок к уникальности) вариант - использовать uniqid() в сочетании с функцией md5():

// Строка длиной в 32 символа
// Например: b100eaee3c552beb1a83aa4927f012c9
$fileName = md5(uniqid());

Вместо uniqid() можно использовать другую функцию, например, microtime(). Эта функция возвращает текущую метку времени Unix с микросекундами:

$fileName = md5(microtime());

// С точностью до микросекунд
$fileName = md5(microtime(true));

Усложним пример (придадим больше уникальности):

$fileName = md5(microtime() . rand(0, 1000));

Если необходимо имя короче, чем 32 символа, то можно просто обрезать строку до нужной длины:

// Строка длиной в 15 символов
$fileName = substr(md5(microtime() . rand(0, 1000)), 0, 15);

Если проект небольшой или даже средний, то вышеуказанные примеры вполне себе годятся для генерации уникальных имён файлов. Но, если проект сложный и очень много файлов загружается, то есть вероятность перезаписи какого-либо файла новым файлом при случайной генерации такого же имени для нового файла. Появляется проблема неконтролируемости уникальности файлов. Иными словами, встаёт необходимость проверки на отсутствие такого же файла. Приведу простой пример. Для удобства я соберу весь код в одном файле:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Генерация уникального имени для файла</title>
</head>
<body>
  <form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="image">
  <button type="submit">Загрузить</button>
</form>
</body>
</html>

<?php
// Генерация уникального имени для файла
function randomFileName($extension = false)
{
  $extension = $extension ? '.' . $extension : '';  
  do {
    $name = md5(microtime() . rand(0, 1000));
    $file = $name . $extension;
  } while (file_exists($file));

  return $file;
}

// Загружаем файл
if ($_FILES) {
  $path = 'uploads/';
  $extension = strtolower(substr(strrchr($_FILES['image']['name'], '.'), 1));
  $file = $path . randomFileName($extension);
  move_uploaded_file($_FILES['image']['tmp_name'], $file);
}

Здесь осуществляется проверка на существование файла. Если файл с таким именем уже существует, то генерируется следующее имя.

Есть ещё вариант - использовать функцию sha1_file(). Она возвращает хеш - 40-символьное шестнадцатеричное число:

if ($_FILES) {
  $path = 'uploads/';
  $extension = strtolower(substr(strrchr($_FILES['image']['name'], '.'), 1));
  $name = substr(sha1_file(microtime() . rand(0, 1000)), 0, 15); // Обрежу до 15-ти символов
  $file = $path . $name . '.' .$extension;
  move_uploaded_file($_FILES['image']['tmp_name'], $file);
}

Или с проверкой на отсутствие файла с таким же именем:

<?php
// Генерация уникального имени для файла
function randomFileName($extension = false)
{
  $extension = $extension ? '.' . $extension : '';  
  do {
    $name = substr(sha1_file(microtime() . rand(0, 1000)), 0, 15);
    $file = $name . $extension;
  } while (file_exists($file));

  return $file;
}

// Загружаем файл
if ($_FILES) {
  $path = 'uploads/';
  $tmp_name = $_FILES['image']['tmp_name'];
  $extension = strtolower(substr(strrchr($_FILES['image']['name'], '.'), 1));
  $file = $path . randomFileName($extension);
  move_uploaded_file($tmp_name, $file);
}

Есть ещё вариант - генерировать уникальное имя для файла, при этом в имени будут и директории:

<?php
// Генерация уникального имени для файла
function randomFileName($extension = false)
{
  $extension = $extension ? '.' . $extension : '';  
  $hash = substr(sha1_file(microtime() . rand(0, 1000)), 0, 15);
  do {
    $name = substr_replace($hash, '/', 3, 0);
    $name = substr_replace($name, '/', 7, 0);
    $file = $name . $extension;
  } while (file_exists($file));

  return $file;
}

// Загружаем файл
if ($_FILES) {
  $path = 'uploads/';
  $tmp_name = $_FILES['image']['tmp_name'];
  $extension = strtolower(substr(strrchr($_FILES['image']['name'], '.'), 1));
  $file = randomFileName($extension);
  $dir = substr($file, 0, 16);
  if (!is_dir($dir)) mkdir($path . $dir, 0777, true);
  move_uploaded_file($tmp_name, $path . $file);
}

Название файла будет примерно таким: uploads/7ce/824/286eeca87.jpg Причём uploads/7ce/824/ это вложенные директории. В примере указано, что если этих директорий нет, то их необходимо создать.

Комментарии временно оключены

Поиск

Популярное