Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

sunergetic's avatar

Generate a unique random string for the database

During my current project i have a need for generating alot of unique keys like API keys or all kinds of tokens. I was surprised that Laravel did not implement something this trivial already, so i decided to create a helper for myself.

You may use this helper for you own projects if you like.

How -to use:

If you dont have a helper file already, you can you create a file like app/Helpers/string.php.

There paste this code:

<?php

if( ! function_exists('unique_random') ){
    /**
     *
     * Generate a unique random string of characters
     * uses str_random() helper for generating the random string
     *
     * @param     $table - name of the table
     * @param     $col - name of the column that needs to be tested
     * @param int $chars - length of the random string
     *
     * @return string
     */
    function unique_random($table, $col, $chars = 16){

        $unique = false;

        // Store tested results in array to not test them again
        $tested = [];

        do{

            // Generate random string of characters
            $random = str_random($chars);

            // Check if it's already testing
            // If so, don't query the database again
            if( in_array($random, $tested) ){
                continue;
            }

            // Check if it is unique in the database
            $count = DB::table($table)->where($col, '=', $random)->count();

            // Store the random character in the tested array
            // To keep track which ones are already tested
            $tested[] = $random;

            // String appears to be unique
            if( $count == 0){
                // Set unique to true to break the loop
                $unique = true;
            }

            // If unique is still false at this point
            // it will just repeat all the steps until
            // it has generated a random string of characters

        }
        while(!$unique);


        return $random;
    }

}

After that, go to composer.json and add this code to the "autoload" block:

"autoload": {
        "classmap": [
            "database"
        ],

        "files": [
            "app/Helpers/string.php" // <-- Add this
        ],
        "psr-4": {
            "App\\": "app/"
        }
    },

Run the following command:

composer dump-autoload

Now you should be able to use it as:

$uniqueString =  unique_random('users', 'auth_token', 40);
0 likes
8 replies
ohffs's avatar

Do you need to check that a 40-char random string has collisions? Do you have an astonishing number of unique strings to deal with? I'm just thinking of your example 40 random alphanum chars the number of possibilities is ([a-z] * [A-Z] * [0-9]) ^ 40 == (26 * 26 * 10) ^ 40 == a huge number :

86106723393064612671464632171892202664634613760000000000000000000000\
000000000000000000

Just seems a little overkill for something that remote - I can see the use for maybe a 4-digit one or something? Just wondering what your use-case is really (say instead of a uuid or sha* hash) :-)

kfirba's avatar

@sunergetic @ohffs if you want to ensure 99.999% unique string you can do something like:

  • generate random 60 characters
  • append the microtime function's result to it
  • run it through a hashing algorithm such as md5/sha1/etc
  • pad the string to the desired amount

The change to get a collision here is so small as you can safely assume there isn't such a string. Adding the microtime results here AND padding it again basically ensures that

ohffs's avatar

@kfirba I know - that's why I was asking what the use case was rather than using a hash function ;-)

sunergetic's avatar

@kfirba @ohffs The function creates a unique string to store in the database, similar to the validation unique:users,email. Because it validates the result in the database, it is guarantueed that the output is 100% unique, because no assumations are made.

For my use case anything below 100% chances of being unique is a no-no. Over time ID's maybe re-generated.

@dpde uuids are probably great, but for my use-case i don't need any non-alpha numeric characters

Here are some sample outputs for my use case:

RdWITIZE4jyJAnZcGhhbtJKEKniPxw2WQGErXqna
wZKl3vokGcOo60j37rWauS8jIZC9JeuXEQb4hwfV
mk8h94ynhQgPTYQRLocckMvYKGzFSW3LFN8vgV9K

You get the basic idea :)

kfirba's avatar

@sunergetic my "solution" can be safely treated as 100% unique.

Do the math, generating 60 random characters, the collision chance is 1.596608e-228 now add the microtime() result to that - what's the chance that in 1 MS you proccessed a whole new request and generated random 60 characters? Almost impossible. now lets shorten that by running it through a fast hash function and pad it to the desired amount, another 8 characters. The change to get a collision in those 8 characters is 2.2931182e-29.

Now calculating the chance to get a collision in total, omitting the chance to get the same result from microtime (which makes the chance of collision much much much Lowe) is 3.66121e-259. Oh yea, if we want to deduct it even further, make the initial string longer than 60 characters. If you need more than 40 characters in total, that deduct the change even further. That means 0% of collision - just saying.

ohffs's avatar

@sunergetic I think you're aiming for 100% where it's very hard to achieve compared to 99.99999999999999% :-) For instance if I use your code I can get two of the same "unique" strings in two requests - again it's very unlikely, but it's a chunk of code that just replicates a good hash. Eg,

GET /save
$unique_thing = unique_random('users', 'auth_token', 40);
// do some stuff
$user->auth_token = $unique_thing;
$user->save();

If two requests come in very close together during the 'do stuff' part then both could get the same unique_thing. If you see what I mean, I think the unique_random function is giving you a false sense of '100%' compared to just $unique_thing = well_known_hash_function(); which equally could get the same value, but without hitting the DB at all or giving any sense of a guarantee (beyond well understood mathematics).

sunergetic's avatar

@ohffs @kfirba You both have good points! I'm pretty sure that everything the human makes can be broken. For my particular use case there is no point in fixing it, because it's not broken :)

Please or to participate in this conversation.