Better Random Generating PHP

2019-01-14 21:26发布

问题:

I know that just using rand() is predictable, if you know what you're doing, and have access to the server.

I have a project that is highly dependent upon choosing a random number that is as unpredictable as possible. So I'm looking for suggestions, either other built-in functions or user functions, that can generate a better random number.

I used this to do a little test:

$i = 0;

while($i < 10000){
    $rand = rand(0, 100);

    if(!isset($array[$rand])){
        $array[$rand] = 1;
    } else {
        $array[$rand]++;
    }

    sort($array);
    $i++;
}

I found the results to be evenly distributed, and there is an odd pattern to the number of times each number is generated.

回答1:

Adding, multiplying, or truncating a poor random source will give you a poor random result. See Introduction to Randomness and Random Numbers for an explanation.

You're right about PHP rand() function. See the second figure on Statistical Analysis for a striking illustration. (The first figure is striking, but it's been drawn by Scott Adams, not plotted with rand()).

One solution is to use a true random generator such as random.org. Another, if you're on Linux/BSD/etc. is to use /dev/random. If the randomness is mission critical, you will have to use a hardware random generator.



回答2:

random.org has an API you can access via HTTP.

RANDOM.ORG is a true random number service that generates randomness via atmospheric noise.



回答3:

I would be wary of the impression of randomness: there have been many experiments where people would choose the less random distribution. It seems the mind is not very good at producing or estimating randomness.

There are good articles on randomness at Fourmilab, including another true random generator. Maybe you could get random data from both sites so if one is down you still have the other.

Fourmilab also provides a test program to check randomness. You could use it to check your various myRand() programs.

As for your last program, if you generate 10000 values, why don't you choose the final value amongst the 10 thousand? You restrict yourself to a subset. Also, it won't work if your $min and $max are greater than 10000.

Anyway, the randomness you need depends on your application. rand() will be OK for an online game, but not OK for cryptography (anything not thoroughly tested with statistical programs will not be suitable for cryptography anyway). You be the judge!



回答4:

Variation on @KG, using the milliseconds since EPOCH as the seed for rand?



回答5:

Another way of getting random numbers, similar in concept to getting UUID

PHP Version 5.3 and above

openssl_random_pseudo_bytes(...)

Or you can try the following library using RFC4122



回答6:

A new PHP7 there is a function that does exactly what you needed: it generates cryptographically secure pseudo-random integers.

int random_int ( int $min , int $max )

Generates cryptographic random integers that are suitable for use where unbiased results are critical (i.e. shuffling a Poker deck).

For a more detailed explanation about PRNG and CSPRNG (and their difference) as well as why your original approach is actually a bad idea, please read my another highly similar answer.