PHP has a uniqid function, that creates a unique identifier. This function is sometimes used in a security context, such as for creating tokens for sessions or CSRF protection. This makes it interesting to know how it works exactly and whether we can predict its output.

Uniqid returns the current time

The source can be found in uniqid.c and is basically this:

PHP_FUNCTION(uniqid)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return strpprintf(0, "%08x%05x", tv.tv_sec, tv.tv_usec);
}

It retrieves the current time consisting of seconds and microseconds, and returns them in hexadecimal form. The output of uniqid consists of the current time.

Sleep a microsecond to avoid doubles

You may have noticed that the current time in microseconds may give the same result twice if we call the function within the same microsecond. To avoid this, uniqid has a call to usleep in it:

PHP_FUNCTION(uniqid)
{
    struct timeval tv;
    usleep(1);
    gettimeofday(&tv, NULL);
    return strpprintf(0, "%08x%05x", tv.tv_sec, tv.tv_usec);
}

This delays execution for one microsecond, causing the result of uniqid to be truly unique.

Except when calling it in parallel. If two processes call uniqid at the same time, they will both sleep for a microsecond and still return the same value.

On Windows, there is no usleep function, and PHP does not implement any alternative. It simply skips the call to usleep, causing uniqid to return the same value every time it is called within the same microsecond. Except on Cygwin, where it raises an error.

Prefix and more entropy parameters

The uniqid function has two parameters: prefix and more_entropy. Prefix is just a string that is prepended to the output.

If the more_entropy parameter is true, some pseudorandom value is appended to the output. This value is generated by calling php_combined_lcg, which corresponds to PHP’s lcg_value. Here, “lcg” stands for linear congruential generator, which is a type of pseudorandom number generator. It is not secure and can be easily cracked.

Conclusion

As we have seen the result of uniqid is not always unique and can be fairly easily predicted, since it is just the current time in hexadecimal.