Действительно уникальное случайное число генерируется с помощью php?

Я создал скрипт php для размещения большого количества изображений, загружаемых пользователем, каков наилучший способ создания случайных чисел для имен файлов изображений, чтобы в будущем не было конфликта имен файлов? Будь как Imageshack. Благодарю.

10 ответов

Решение

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

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

$better_token = uniqid(md5(mt_rand()), true);

Самым простым способом будет новый GUID для каждого файла.

http://www.php.net/manual/en/function.uniqid.php

Вот как я реализовал ваше решение

В этом примере предполагается, что я хочу

  • Получить список, содержащий 50 чисел, уникальных и случайных, и
  • Этот список # поступить из диапазона номеров от 0 до 1000

Код:

 //developed by www.fatphuc.com

 $array = array(); //define the array

 //set random # range
 $minNum = 0;
 $maxNum = 1000;

// i just created this function, since we’ll be generating
// # in various sections, and i just want to make sure that
// if we need to change how we generate random #, we don’t 
// have to make multiple changes to the codes everywhere. 
// (basically, to prevent mistakes)

function GenerateRandomNumber($minNum, $maxNum){
   return round(rand($minNum, $maxNum));
}

//generate 49 more random #s to give a total of 50 random #s
for($i = 1; $i <= 49; $i++){
    $num1 = GenerateRandomNumber($minNum, $maxNum);   
        while(in_array($num1, $array)){
            $num1 = GenerateRandomNumber($minNum, $maxNum);
        }   
    $array[$i] = $num1;
}

asort($array); //just want to sort the array

//this simply prints the list of #s in list style
echo '<ol>';
foreach ($array as $var){
    echo '<li>';
    echo $var;
    echo '</li>';
}
echo '</ol>';

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

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

Если известно, что обнаружение дубликатов не является проблемой, то я все равно рекомендую этот подход, но изменяю выходные данные на основе обнаруженных коллизий (но используя гораздо более дешевый метод вычисления, чем тот, который был предложен Lo'oris), например

 $candidate_name=generate_hash_of_file($input_file);
 $offset=0;
 while ((file_exists($candidate_name . strrev($offset) && ($offset<50)) {
    $offset++;
 }
 if ($offset<50) {
    rename($input_file, $candidate_name . strrev($offset));
 } else {
    print "Congratulations - you've got the biggest storage network in the world by far!";
 }

это даст вам возможность хранить около 25*2^63 файлов с использованием хэша sha1.

Что касается того, как генерировать хеш, чтение всего файла в PHP может быть медленным (особенно если вы пытаетесь прочитать все это в одну строку, чтобы хэшировать его). Большинство систем Linux/Posix/Unix поставляются с такими инструментами, как 'md5sum', которые очень эффективно генерируют хэш из потока.

C.

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

  1. подделать имя файла
  2. попробуйте открыть этот файл
  3. если он существует, переходите к 1
  4. создать файл

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

Гарантированная уникальность не может быть случайной. Случайное не может быть гарантировано уникальным. Если вы хотите уникальный (без случайного), тогда просто используйте целые числа: 0, 1, 2, ... 1235, 1236, 1237, ... Определенно уникальный, но не случайный.

Если это не устраивает, то вы можете быть совершенно уникальным с появлением случайных. Вы используете шифрование целых чисел, чтобы они выглядели случайными. Использование DES даст вам 32-битные числа, в то время как использование AES даст вам 64-битные числа. Используйте либо для шифрования 0, 1, 2,... в порядке с тем же ключом. Все, что вам нужно сохранить, это ключ и следующий номер для шифрования. Поскольку шифрование является обратимым, то зашифрованные номера гарантированно уникальны.

Если 64-битные или 32-битные числа слишком велики (32 бита - это 8 шестнадцатеричных цифр), посмотрите на формат, сохраняющий шифрование, который даст вам меньший размерный диапазон при некоторых затратах времени.

Моим решением обычно является хеш (MD5/SHA1/...) содержимого изображения. Это дает дополнительное преимущество: если люди загружают одно и то же изображение дважды, у вас остается только одно изображение на жестком диске, что экономит некоторое пространство (конечно, вы должны убедиться, что изображение не удалено, если один пользователь удаляет его, а другой пользователь имеет то же изображение в использовании).

Другие вопросы по тегам