Multiple uniqid () calls are not unique

I have an interesting example where multiple retries uniqid()

do not generate unique numbers when hosted locally on XAMPP. The unique identifier is repeated somewhere between 5-20 times and then mysteriously changes.

However, as an interesting twist, the code works great on our production server.

So here's what I do: I create a wrapper that, when clicked, hides / hides the child content in a div via a simple javascript function. Since the div to hide is dynamically generated, it is referenced by a unique ID that is generated by PHP.

An example of the problem looks like this:

// Replace something like '[element] => <newline> (' with <a href="javascript:toggleDisplay('[unique id]');">...</a><div id="[unique id]" style="display: none;">   
$out = preg_replace_callback(
        $regex,
        function ($matches) {
            $id = uniqid();
            return $matches[1] . "<a class='debug' href='javascript:toggleDisplay(\"" . $id . "\");'>" . $matches[2] . "</a>" . "<div id='" . $id . "' style='display: none'>";
        }, $out
    );

      

The javascript function is as follows (just so you can see what I am doing, it works great):

<script language="Javascript">
    function toggleDisplay(id) {
        document.getElementById(id).style.display = (document.getElementById(id).style.display == "block") ? "none" : "block";
    }
</script>'

      

The problem is that the output divs all have the same unique id (!!), in clusters somewhere between 5-15, so javascript doesn't know which div is being referenced.

So, some things I found: If I do something like $id = uniqid() . rand(10000,99999)

instead of just $id = uniqid()

, then the code works again as intended. So I'm pretty sure the problem is that uniqid()

it doesn't actually generate a unique ID, given that I'm not overwriting or reusing the variable $id

.

Another interesting thing I found: if I repeat microtime()

together with uniqid()

, uniqid()

only changes on change microtime()

. It sounds like a hint to me.

So my question is , why does it uniqid()

sometimes generate uniqid()

? uniqid()

Should n't it generate a unique number even if microtime()

it's the same? Is this behavior well documented or well known? Or is there something else I am missing?

I ask because I am uncomfortable to use uniqid()

because I do not understand the basic behavior.

Any insight will be greatly appreciated. Thank.

+3


source to share


2 answers


The result is uniqid()

not guaranteed to be unique, and your research microtime()

will really tell you why.

According to the man page foruniqid()

, he:

Gets a prefix unique identifier based on the current time in microseconds.

Thus, the main input is indeed the current "microtime". However, it also accepts an additional parameter:

more_entropy

If set to TRUE, uniqid () will add additional entropy (using the combined linear congruential generator) at the end of the return value, increasing the likelihood that the result will be unique.

Note that even with this argument, the manual is careful not to guarantee uniqueness, but as with manual usage rand()

, it adds an additional source of randomness that makes collisions much more unlikely.



To confirm, we can look at the source code for the function , where we can see that the unset output more_entropy

is really just a hexadecimal representation of the current microsecond timestamp. Interesting note:

#if HAVE_USLEEP && !defined(PHP_WIN32)
    if (!more_entropy) {
#if defined(__CYGWIN__)
        php_error_docref(NULL, E_WARNING, "You must use 'more entropy' under CYGWIN");
        RETURN_FALSE;
#else
        usleep(1);
#endif
    }
#endif

      

So, if you're not on Windows, the function will try to sleep for a microsecond to force other values ​​to differ.

This makes it the wrong idea to run uniqid()

many times in a row, because if it does, it will do it slowly. (It takes either a microsecond of sleep or a call to the random number generator.)

Your best bet is to use it once to create an arbitrary prefix, and then just increment the counter for each element, which might look something like this:

$id_prefix = uniqid();
$id_suffix = 0;
$out = preg_replace_callback(
        $regex,
        function ($matches) use ($id_prefix, &$id_suffix) {
            $id = $id_prefix . $id_suffix;
            $id_suffix ++;
            return $matches[1] . '... some html ...' . $id . ' ... ';
        },
        $out
);

      

+9


source


From uniqid () documentation

Warning This function does not generate random or unpredictable strings. This feature should not be used for security reasons. Use cryptographically secure random function / generator and cryptographically secure hash functions to generate unpredictable secure identifiers.

If the OS the script is running on does not provide a very good clock resolution, then uniqid () may return the same value multiple times in a row.



You could also use $id = uniqid(rand(10000,99999))

or to further increase the chances of accidents: $id = uniqid(rand(10000,99999), true)

.

Anyway, the takeaway is that the name is misleading as it doesn't guarantee that you will get unique values ​​every time the function is called.

+2


source







All Articles