(PHP 4, PHP 5)
srand — 播下随机数发生器种子
$seed
] )
用 seed
播下随机数发生器种子。seed
参数没有给出时,会被设为随时数。
Note: 自 PHP 4.2.0 起,不再需要用 srand() 或 mt_srand() 给随机数发生器播种 ,因为现在是由系统自动完成的。
seed
可选的种子值
没有返回值。
版本 | 说明 |
---|---|
Since 4.2.0 |
seed 成为可选,省略时会默认使用随机值。
|
Example #1 srand() 例子
<?php
// seed with microseconds
function make_seed()
{
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}
srand(make_seed());
$randval = rand();
?>
dev+php at alepe dot com (2011-05-18 18:34:07)
Be sure to "reset" srand() to a random seed once you use it (if you don't need the seed after that).
For example:
<?php
function myRandomArray(&$array, $seed) {
srand($seed);
shuffle($array);
}
//...
myRandomArray($array, 12345);
//...
//...
//...
$y = rand(0,100); //<-- Will always return the same sequence as srand is still on effect.
?>
To prevent that, one way is to set the srand() back to "normal":
<?php
function myRandomArray(&$array, $seed) {
srand($seed);
shuffle($array);
srand(); //<-- this would do the trick
}
?>
This also applies for mt_srand().
Niels Keurentjes (2011-02-25 05:22:33)
Keep in mind that the Suhosin patch which is installed by default on many PHP-installs such as Debian and DirectAdmin completely disables the srand and mt_srand functions for encryption security reasons. To generate reproducible random numbers from a fixed seed on a Suhosin-hardened server you will need to include your own pseudorandom generator code.
harmen at no dot spam dot rdzl dot nl (2009-04-10 10:53:52)
To generate a random number which is different every day, I used the number of days after unix epoch as a seed:
<?php
srand(floor(time() / (60*60*24)));
echo rand() % 100;
?>
My provider upgraded the php server recently, and calling srand(seed) does not seem to set the seed anymore. To let srand set the seed, add the following line to your .htaccess file
php_value suhosin.srand.ignore 0
Kudos to doc_z (http://www.webmasterworld.com/php/3777515.htm)
Harmen
php at capuzza dot net (2007-07-11 04:24:17)
Richard's statement, that calling srand more than once per script will impair you chance to get a true random number, is not necessarily correct. In fact using srand more than once can even improve randomness if you understand how.
The rand function uses a certain algorithm to calculate a number out of the seed given to srand. This algorithm, of course, is always the same, so without knowing the seed (which is assumed to be random) you can calculate any value returned by rand other than the first one if you know the first one. The chances to do so get better the higher the range of your random number is (and are pretty good if the range of the random number exceeds the possible range of the seed).
In the following example the range of the desired random number is 10 times higher than the possible range of the seed:
<?
list($usec, $sec) = explode(" ", microtime());
srand((int)($usec*10));
$rand_value = rand(0, 99);
echo($rand_value."<br>");
$rand_value = rand(0, 99);
echo($rand_value."<br>");
$rand_value = rand(0, 99);
echo($rand_value."<br>");
?>
The code will return 3 numbers. Execute the code several times and write down each set of numbers, you will notice that after a short time you will know the second and the third number by only seeing the first one and compare it to what you've written down. All that without knowing the random seed! Of course seeding with (double)microtime()*1000000 gives a 100,000 times higher range, but if the range of the random numbers you want to generate was 100,000 times higher too, it's just a matter of time for someone being able to predict all your random numbers after the first one.
But simply calling srand in between the rands wouldn't do the trick either, because the execution time of the code in between the srands is highly predictable. The key is to do something before each call of srand, which has a real random time of execution. Requesting a website from another server would be such a thing (can also be a SQL request or something).
<?
list($usec, $sec) = explode(" ", microtime());
srand((int)($usec*10));
$rand_value = rand(0, 99);
echo($rand_value."<br>");
$foo=file_get_contents
("http://www.google.com/search?q=sea
rch+term+does+not+matter&hl=en");
list($usec, $sec) = explode(" ", microtime());
srand((int)($usec*10));
$rand_value = rand(0, 99);
echo($rand_value."<br>");
$foo=file_get_contents
("http://www.google.com/search?q=sea
rch+term+still+does+not+matter&hl=en");
list($usec, $sec) = explode(" ", microtime());
srand((int)($usec*10));
$rand_value = rand(0, 99);
echo($rand_value."<br>");
?>
You can probably execute this code a thousand times with hardly getting any set of 3 numbers repeated. Try what you did with the other code snippet above and note that you improved randomness by using srand more than once.
Via http://www.capuzza.com/detail.php?ID=115293
bootc at bootc dot net (2005-06-06 08:03:11)
OK, to summarize what people have been saying so far:
1. DO NOT seed the RNG more than once if you can help it!
2. You HAVE TO seed the RNG yourself if you are using PHP < 4.2.0.
3. Using a prime multiplier to microtime() probably does very little. Use the Mersenne Twister instead.
4. You can use the Mersenne Twister PRNG with the mt_rand and mt_srand functions. This is faster and is more random.
corey at eyewantmedia dot com (2005-01-06 08:22:55)
Hey, I use rand() all the time to get a rough probability of something happening. I went ahead and wrote a little function to help with the situation "I wish this thing would happen 2% of the time, so here is 5 lines of code to figure it out" since I run into it so much. Obviously, this is pretty similar to the if rand($x, $y) <$soething way, but I find it a little more flexible.
/**
* @return boolean
* @param int $baseChance
* @param int $chanceAmplifier
* @desc Returns a true or false value based on a whether a random number
* in the range 1 - (100 * $chanceAmplifier) is less than $baseChance.
*/
function RandomChance($baseChance, $chanceAmplifier = 1) {
srand( ((int)((double)microtime()*1000003)) ); // get a good seed
$totalBag = 100 * $chanceAmplifier; // set up max limit
$probCheck = rand(1,$totalBag); // get random number
if ( ($probCheck < $baseChance) ) { //compare it to $baseChance
$result = true;
} else {
$result = false;
}
return $result; //Yay!
}
davidaylmer zebra gmail.com (zebra = at) (2005-01-03 06:42:53)
Just for the convienience of others...
1000003 is a prime number
So (double)microtime()*1000003 may work better for some applications.
edublancoa at gmail dot com (2004-12-23 01:39:48)
Another use of srand is to obtain the same value of rand in a determined time interval. Example: you have an array of 100 elements and you need to obtain a random item every day but not to change in the 24h period (just imagine "Today's Photo" or similar).
<?php
$seed = floor(time()/86400);
srand($seed);
$item = $examplearray[rand(0,99)];
?>
You obtain the same value every time you load the page all the 24h period.
no at spam dot com (2004-09-01 16:59:59)
I simply use this, and it has always worked fine:
function initRand ()
{
static $randCalled = FALSE;
if (!$randCalled)
{
srand((double) microtime() * 1000000);
$randCalled = TRUE;
}
}
function randNum ($low, $high)
{
initRand();
$rNum = rand($low, $high);
return $rNum;
}
Codaholics dot com (2004-06-16 10:59:59)
office's comment about multiplying by 1234567 instead of 1000000 is slightly misguided for a couple of reasons.
first, as the editor note would indicate, 1234567 is not a prime number.
second, the problem he is attempting to fix is that the random values are slowly converging. this, however, is not a problem with the seeding of the random number generator, but a problem with the RNG itself. most default RNGs that come with programming languages will converge because they were written for efficiency and to function in everyday programs.
if you need a Pseudo Random Number Generator (PRNG) that is cryptographically secure and does not converge after repeated use without seeding... you will unfortunately have to use a different generator. There are several out there such as the MersenneTwister, Yarrow (by Bruce Schneierer of Counterpane Security) and more being made every day. Due to the hassle of finding a reputable PRNG, it is recommended that you only need to use those for issues that require strong security such as gambling games and cryptography.
hope this cleared things up :)
vinod at todays-deals dot com (2002-10-19 13:57:30)
hi,
Here is one useful function that returns random string for given length
//#########################//
function randomstring($len)
{
srand(date("s"));
while($i<$len)
{
$str.=chr((rand()%26)+97);
$i++;
}
$str=$str.substr(uniqid (""),0,22);
return $str;
}
$rand_value=randomstring(10);
//#########################//
Thanks
Vinod
http://www.todays-deals.com
office at at universalmetropolis dot com (2002-04-26 14:40:44)
[Editor's note: 1234567 is NOT a prime number]
I created an application that requires millions of different random values replicating dice and have found over substantial time, the numbers even up towards the middle.
May I suggest rather than this:
(double)microtime()*1000000
Use this instead:
(double)microtime()*1234567
1000000 is an even number, divisible by almost anything. 1234567 is a prime number and is hence uneven so it gives a little more flexibility with range.
Don't know if this change was the main reason for affecting the application, but it seemed to help.
ceo at l-i-e dot com (2002-02-22 17:53:23)
In addition to my earlier post being stupidly coded with $wasseeded = TRUE :-| here is an update:
In PHP4, I *BELIEVE* the random number generator will seed itself if you don't seed it.
In PHP3, or some versions of PHP3?, that was not the case -- An unseeded rand() wouldn't be random.
While it would "work fine" in terms of spitting out a number, an unseeded random number generator won't be very random in many situations unless it has been properly seeded.
I'm afraid I can't explain all the details of why this is because A) it would be an entire textbook, and B) I don't know them all by heart, even if I understood them 20 years ago in college.
If you are running PHP4, you are probably okay, and if you are happy with the randomness of your values, you are fine, but you may want to do a little test like:
<?php
$stats[1] = 0;
$stats[2] = 0;
$stats[3] = 0;
for ($i = 0; $i < 1000; $i++){
$choice = rand(1,3);
if (!$i){
echo "First random choice: $choice<BR>\n";
}
$stats[$choice]++;
}
reset($stats);
while (list($num, $count) = each($stats)){
echo "$num: $count<BR>\n";
}
?>
Run the test a half-dozen times and check that the distribution of 1, 2, and 3 is even, and that the first number chosen is not the same every time.
This is hardly an exhaustive test, but it at least gives some reassurance that the numbers aren't completely predictable.
You may also wish to switch to http://php.net/mt_rand which is faster (if you generate a *LOT* of numbers) and allegedly a "better" (more random) function.
Again, it would be an entire book to explain why mt_rand is "more random"...
YMMV. If you're doing "Casino Slots" with real money, you'd better do your homework on this. If you're giving away a free CD or something silly, who cares?
sinister at cyberfrag dot com (2002-01-21 11:08:15)
It's pretty easy how he's getting a highly random number. Microtime measures the time since the Epoch (0:00:00 January 1, 1970 GMT). Microtime() returns a string of 2 parts, the current microsecond count, a space, and then the time since the Epoch. By using (double), he chops off the seconds-since-Epoch time, and uses the "current microsecond count" until the next second.
Since time moves constantly, microseconds is the smallest unit a programming language makes use of, the current microseconds up until the next second will give you a million different numbers, every second. Now simply multiply the 0.xxxxxx number by 1,000,000 (like back in Jr. High School), and it will niftily place the 0.xxxxxx number in xxxxxx fashion for your seed.
mlwmohawk at mohawksoft dot com (2001-11-02 07:51:56)
srand() is pretty tricky to get right. You should never seed a random number generator more than once per php process, if you do, your randomness is limited to the source of your seed.
The microtime function's micro-seconds portion has a very finite resolution, that is why the make_seed function was added to the document. You should never get the same seed twice.
In the later CVS versions, PHP will seed the random generator prior to performing a rand() if srand() was not previously called.
trobinson-a-t-gksystems-d-o-t-com (2001-11-02 02:26:58)
The need to seed.
You might run a script like this:
echo mt_rand(0,99999999);
a bunch of times, say by pressing Refresh in the browser, and get a different result each time. That is dependent on your web server. If the same apache/mod-php process lives through several invocations of the script, it won't reset the seed each time. But every php process will start with the same seed. If php is invoked as an external cgi, seed will always be the same. So... always seed!
php_public at macfreek dot nl (2001-10-07 08:52:47)
The make_seed() function in the example code is VERY bad, and is in fact responsible for seeding always the same value, so that the output of rand() is the same with every page reload (!)
ALWAYS use:
(double)microtime()*1000000
See for more details my note on the mt_srand() page [ function.mt_srand.php ]
houtex_boy-at-yahoo-dot-com (2001-10-05 17:52:48)
The above function ^ will never execute anything. It should be something like this:
function my_srand($seed = '')
{
static $wascalled = FALSE;
if (!$wascalled){
$seed = $seed === '' ? (double) microtime() * 1000000 : $seed;
srand($seed);
$wascalled = TRUE;
}
}
ceo at l-i-e dot com (fka richard at zend dot com) (2001-08-24 22:58:52)
Here is a way to be sure you only call srand once:
function my_srand($seed = ''){
static $wascalled = TRUE;
if (!$wascalled){
$seed = $seed === '' ? (double) microtime() * 1000000 : $seed;
srand($seed);
}
}
(2001-08-14 22:14:59)
I have a ramdon circulater that changes a piece of text once a day, and I use the following code to make sure the see is unique enough.
$tm = time();
$today = mktime(0, 0, 0, (int)date("n", $tm), (int)date("j", $tm), (int)date("Y", $tm));
srand($today / pi());
The pi works wonders for the whole thing and it works like a charm. Any other big decimal number will do as well, but pi is the most common "big" number.
akukula at min dot pl (2001-08-14 07:14:19)
Calling srand((double)microtime()*1000000),
then $a=rand(1000000,9999999), then srand((double)microtime()*$a)
adds nothing to the entrophy: the execution time of rand and srand is
constant, so the second microtime() produces nothing really fascinating. You may safely use just the first srand().
vonStahl at NOPE2SPAM dot ratio dot net (2001-07-27 05:32:13)
How about<br>
<?
srand((double)microtime()*1000000);
$seed = rand(1000000,9999999);
srand((double)microtime()*$seed);
$yadda = rand (1,100);
?><br>
I used this in a test run with 1,000.000 calls for $yadda. Processing time increased by 0.0000061 seconds compared to a simple "srand((double)microtime()*1000000);"
$yadda had the value of each number between 1 and 100 for between 0.99999122% and 1.00000872% of all calls. That's random and fast enough for me. :)
rjones at ditzed dot org (2001-05-29 12:02:45)
As a sidenote on the usage of srand():
If you are making use of modular programming, it is probably better to try and call the srand routine from the parent script than from any modules you may be using (using REQUIRE or INCLUDE).
This way you get around the possibility of calling srand() more than once from different modules.
The flaw in this solution, of course, is when using modules produced by another programmer, or when producing modules for another programmer.
You cannot rely on another programmer calling the srand function before calling the modular function, so you would have to include the srand function inside the module in this case.
If you produce modules for use by other programmers then it is good practice to documentise the fact you have already called the srand function.
Or if you use a modular function produced by someone else, check their documentation, or check their source code.
rjones at ditzed dot org (2001-05-29 11:41:56)
Use the srand() seed "(double)microtime()*1000000" as mentioned by the richard@zend.com at the top of these user notes.
The most notable effect of using any other seed is that your random numbers tend to follow the same, or very similar, sequences each time the script is invoked.
Take note of the following script:
<?php
srand($val);
echo rand(0, 20) . ", ";
echo rand(0, 20) . ", ";
echo rand(0, 20) . ", ";
echo rand(0, 20) . ", ";
echo rand(0, 20);
?>
If you seed the generator with a constant, say; the number 5 ($val = 5), then the sequence generated is always the same, in this case (0, 18, 7, 15, 17) (for me at least, different processors/processor speeds/operating systems/OS releases/PHP releases/webserver software may generate different sequences).
If you seed the generator with time(), then the sequence is more random, but invokations that are very close together will have similar outputs.
As richard@zend.com above suggests, the best seed to use is (double) microtime() * 1000000, as this gives the greatest amount of psuedo-randomness. In fact, it is random enough to suit most users.
In a test program of 100000 random numbers between 1 and 20, the results were fairly balanced, giving an average of 5000 results per number, give or take 100. The deviation in each case varied with each invokation.
MakeMoolah at themail dot com (2001-01-28 15:16:15)
Sorry about that... ok, forget have of what I said up there ^.
The code that would prove my example is this:
<?php
srand(5);
echo(rand(1, 10));
srand(5);
echo(rand(1, 10));
srand(5);
echo(rand(1, 10));
?>
Each time you SHOULD get the same answer, but if you did this:
<?php
srand(5);
echo(rand(1, 10));
echo(rand(1, 10));
echo(rand(1, 10));
?>
then the answers would be different, and you'd be letting the random number formula do it's duty.
hagen at von-eitzen dot de (2000-10-10 03:51:12)
It is REALLY essential to make sure that srand is called only once.
This is a bit difficult if the call is hidden somewhere in third-party code you include. For example, I used a standard banner script that *seemed* to work well putting
three random banners in one frame. But in the long run, the choice appeared
somewhat biased - probably because srand was called once per banner, not
once per run.
It would be nice if the random number generator worked like in PERL: If You use the random function without having called srand ever before in a script,
srand is invoked before (and automatically with a nice seed, hopefully).
I suggest that one should do something like this:
<?php
if (!$GLOBALS["IHaveCalledSrandBefore"]++) {
srand((double) microtime() * 1000000);
}
?>
(Depending on the situation, one might also work with a static variable instead)
richard at zend dot com (2000-10-05 12:02:28)
*ALWAYS* use
(double)microtime()*1000000
as your seed.
Do *NOT* just use time(). Do not add an extra 0 to make it "bigger".
Take care to call srand() only *ONCE* per script.
Calling
(double)microtime()*1000000
once, and only once, per script gives you the maximum "randomness" you can get.
Anything else is sub-standard. If you want to understand why, there's a lot of reading you need to do... I don't know enough to point you to the best text to get started on this reading. For now, just trust the PHP Developers, okay?