简体   繁体   中英

truly unique random number generate by php?

I'm have build an up php script to host large number of images upload by user, what is the best way to generate random numbers to image filenames so that in future there would be no filename conflict? Be it like Imageshack. Thanks.

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

Easiest way would be a new GUID for each file.

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

Here's how I implemented your solution

This example assumes i want to

  • Get a list, containing 50 numbers that is unique and random, and
  • This list of # to come from the number range of 0 to 1000

Code:

 //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>';

Keep a persistent list of all the previous numbers you've generated(in a database table or in a file) and check that a newly generated number is not amongst the ones on the list. If you find this to be prohibitively expensive, generate random numbers on a sufficient number of bits to guarantee a very low probability of collision.

You can also use an incremental approach of assigning these numbers, like a concatenation of a timestamp_part based on the current time and a random_part, just to make sure you don't get collisions if multiple users upload files at the same time.

您可以按照上面的建议使用microtime(),然后附加原始文件名的哈希值,以进一步避免在确切的当代上传情况下(罕见)发生冲突。

There are several flaws in your postulate that random values will be unique - regardless of how good the random number generator is. Also, the better the random number generator, the longer it takes to calculate results.

Wouldn't it be better to use a hash of the datafile - that way you get the added benefit of detecting duplicate submissions.

If detecting duplicates is known to be a non-issue, then I'd still recommend this approach but modify the output based on detected collisions (but using a MUCH cheaper computation method than that proposed by Lo'oris) eg

 $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!";
 }

this would give you the capacity to store approx 25*2^63 files using a sha1 hash.

As to how to generate the hash, reading the entire file into PHP might be slow (particularly if you try to read it all into a single string to hash it). Most Linux/Posix/Unix systems come with tools like 'md5sum' which will generate a hash from a stream very efficiently.

C.

  1. forge a filename
  2. try to open that file
  3. if it exists, goto 1
  4. create the file

Using something based on a timestamp maybe. See the microtime function for details. Alternatively uniqid to generate a unique ID based on the current time.

Guaranteed unique cannot be random. Random cannot be guaranteed unique. If you want unique (without the random) then just use the integers: 0, 1, 2, ... 1235, 1236, 1237, ... Definitely unique, but not random.

If that doesn't suit, then you can have definitely unique with the appearance of random. You use encryption on the integers to make them appear random. Using DES will give you 32 bit numbers, while using AES will give you 64 bit numbers. Use either to encrypt 0, 1, 2, ... in order with the same key. All you need to store is the key and the next number to encrypt. Because encryption is reversible, then the encrypted numbers are guaranteed unique.

If 64 bit or 32 bit numbers are too large (32 bits is 8 hex digits) then look at a format preserving encryption which will give you a smaller size range at some cost in time.

My solution is usually a hash (MD5/SHA1/...) of the image contents. This has the added advantage that if people upload the same image twice you still only have one image on the hard disk, saving some space (ofc you have to make sure that the image is not deleted if one user deletes it and another user has the same image in use).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM