Aaron Saray

open source programmer,
web developer

entrepreneur, author
and musician

My Blog

contains PHP, Web and business/entrepreneurial related content. Please join in the conversation!

When uniqid is too slow in PHP

I just profiled some of my code and found out that the biggest chunk of my processing time was used by uniqid(). I use this to generate form tokens to prevent cross site request forgeries. On one page, I have 6 forms each with its own unique uniqid().

The first thought is to just use one ID per page. However, I didn’t want to change too much of my code. It’s working – so lets just make it work faster. I did some thinking and realized that maybe my unique id didn’t need to be THAT unique – just not super predictable. A sha1() hash of a random number should do the trick. And it should be faster. Just to verify, I did my own benchmark using this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$start = $stop = array();

$start['uniqid'] = microtime(TRUE);
for ($x = 0; $x< 1000; $x++) {
    $val = uniqid();
}
$stop['uniqid'] = microtime(TRUE);

$start['mt_rand'] = microtime(TRUE);
for ($x=0; $x<1000; $x++) {
    $val = mt_rand(0, 1000000);
}
$stop['mt_rand'] = microtime(TRUE);

$start['sha1/mt_rand'] = microtime(TRUE);
for ($x=0; $x<1000; $x++) {
    $val = sha1(mt_rand(0, 1000000));
}
$stop['sha1/mt_rand'] = microtime(TRUE);

foreach ($start as $key=>$startval) {
    echo "{$key}: " . ($stop[$key] - $startval) . "<br />";
}

The results:

uniqid: 1.1227629184723
mt_rand: 0.0030300617218018
sha1/mt_rand: 0.0076968669891357

As you can see, sha1/mt_rand combination is so much faster. In fact, 140x! While this is still micro-optimization, running that 6 times to me makes a difference.

Your thoughts? Is this still unique enough for form tokens?

This entry was posted in PHP and tagged . Bookmark the permalink.

7 Responses to When uniqid is too slow in PHP

  1. It seems to me that this should be unique enough for the purpose stated. It’s not like it is being used as a permanent ID for anything, just a one-time token.

    I love it when you can get down to the optimizing tasks. It means that everything is working. :)

  2. Great experiment!
    I agree this could be used for the purpose of tokens. As you stated a token does not need to be ‘unique’ just something not easy to guess. Furthermore it’s not a permanent id such as a user id or password. I say go with it.
    I will be going through some of my code soon to see if I can take advantage of your findings.

  3. JW says:

    If the ‘more_entropy’ parameter is true, uniqid is 4-5x faster than the uniqid without it, plus you have more unique results.

  4. Benjiro says:

    To point a few things out:

    * uniqid with ‘more_entropy’ is about 2.5 a 3 times faster then the standard uniqid

    * Those results are too high ( unless you where running it on a calculator? :) ). When running the exact same code on a Atom 330 machine ( aka, a crap system for speed, but excellent for developing high efficient code ). This Atom system’s results are 6 times faster ( 0.20 ) for the uniqid. And twice for the mt_rand ( 0.0015 ). The one that’s the same time as your system, is the SHA1.

    Tests run a dozen times. Looks to me, that some activity is influencing the results?

    * Fastest “unique” number, is actually mt_rand(0, 1000000) . mt_rand(0, 1000000), with a speed of 0.006 ( in my tests ). Each mt_rand has 0.0015 needed to run, with the joining of both rand taking 0.003.

    * Performance difference between mt_rand(0, 100000) or mt_rand(0, 10000000) is as good as worthless ( +-1% ). Allowing for even less “chance” of hitting the same random number.

    * For all intensive purpose, “mt_rand(0, 100000000) . mt_rand(0, 100000000)” is actually FASTER, then sha1( mt_rand(0, 1000000) ). Its only +- 13 a 18%, but its still faster, and WAY more “unique”.

    * And to be honest, SHA1 has no “use”. If two the same results are presented by the mt_rand, you will get the same sha1 output. sha1 is not a random encryption.

    * Note: used the exact same code as above, just added a few more tests.

    I hope this info is off help…

  5. livingdead says:

    Hi,

    I made several test. adding to your test a collision detection.

    Those scripts are corrupt because they are producting to much collision. Something like 3%

    This is useless. only uniqid is uniqu however you can speed it up regarding this post : http://tjl.co/blog/code/uniqid-speed-test/

    Regards

    • Aaron says:

      Hi – these are great points. You are correct in the collisions – it isn’t meant to be something like a UUID generator or anything like that. The chances of collisions with using them as tokens for a form is a lot less likely. Great link, though!

  6. Oliver says:

    Why take the sha1 of the output of mt_rand()? Sha1() will always return the same hash with a given input so you only have as many unique(ish) ID’s as you have pseudo randoms from your generator. Actually you might even have fewer if there happen to be repeated sha1′s in your range (yes, the probability of that is darn close to zero).

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>