TRiG
TRiG

Reputation: 10643

Generate a readable random unique ID

I need to generate unique transaction IDs. The system allows digits, letters, hyphens, and underscores, but not full stops.

The function I’m currently using is,

generate_id() {
    $id = uniqid('P_', true);
    $id = str_replace('.', '-', $id);
    return $id;
}

Sample output:

P_551171d3dd8a93-57457934

However, I have recently found that (a) uniqid() isn’t necessarily unique, and (b) my customer occasionally needs to retype these IDs, compare them, search for them, etc. The current IDs are not very readable, and are difficult to eyeball. (I had thought that these were purely for internal use in the payment API. I only recently realised that the customer was actually reading the things.)

So I was thinking of changing to this,

function generate_id() {
    $s = '';
    for ($i = 0; $i < 5; $i++) {
        if ($s) {
            $s .= '-';
        }
        $s .= bin2hex(openssl_random_pseudo_bytes(2));
    }
    return $s;
}

Sample output:

ced7-1cef-5331-193c-907d

openssl_random_pseudo_bytes() is the recommended way to generate random unique identifiers, but I fear that doing it four times and concatinating (which I’m doing only because that’s the easiest way to split it up with hyphens for ease of reading) might compromise it. Should I generate one long string and then manipulate it to add hyphens?

Or, indeed, should I do something else altogether? I don’t really mind what the transaction ID looks like, so long as it’s unique and relatively easy to eyeball or retype.

Upvotes: 0

Views: 1778

Answers (2)

Spechal
Spechal

Reputation: 2706

Use a UUID. It can be formed from uniqid() and a custom algorithm or using a library. If you get a collision using UUID, < insert random massive gift here >.

https://github.com/ramsey/uuid

Upvotes: 0

deceze
deceze

Reputation: 521995

Calling openssl_random_pseudo_bytes many times in a row should not be a problem. Whether you read one long string of random bytes or many short strings of random bytes doesn't matter, they're still random. I would still change that code to this, because it's simpler:

join('-', str_split(bin2hex(openssl_random_pseudo_bytes(40)), 4))

This almost looks like a UUID already, so you may actually want to use one of those instead. While random bytes should do, UUIDs are explicitly designed to be globally unique with a high enough probability that you don't need to worry about it in practice at all. Use http://pecl.php.net/package/uuid or your alternative preferred implementation.

Upvotes: 2

Related Questions