21

I am new to laravel 5. I am working on a project where I want to assign some random-readable unique string to each application. I have knowledge of the each application id which may be use as a seed. Since the app is going to be use within the company I don't worry much about security. I expect the table size to grow so my goal is to achieve uniqueness as much as possible because the field in DB is unique. A code like (EN1A20, EN12ZOV etc). If the function can allow me to pass the length of the string I want to return, that would be really awesome.

Edit Shown below is my attempt to the problem

private function generate_app_code($application_id) { 
        $token = $this->getToken(6, $application_id);
        $code = 'EN'. $token . substr(strftime("%Y", time()),2);

        return $code;
    }

    private function getToken($length, $seed){    
        $token = "";
        $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $codeAlphabet.= "0123456789";

        mt_srand($seed);      // Call once. Good since $application_id is unique.

        for($i=0;$i<$length;$i++){
            $token .= $codeAlphabet[mt_rand(0,strlen($codeAlphabet)-1)];
        }
        return $token;
    }

Can the code above do the trick?

Edit

Actually I borrowed ideas from this post PHP: How to generate a random, unique, alphanumeric string? to come out with the methods above but the post does not entirely address my issues. My goal is to generate a string of length say 6 to 8 (Alphanumeric and readable). This string would be use by my admin for query purposes. In my function I have mt_srand($seed) to seed the random number generator where seed is my application_id. It is possible to get duplicate $token.

Appreciate help.

Community
  • 1
  • 1
Fokwa Best
  • 3,322
  • 6
  • 36
  • 51
  • Does this help: http://garrettstjohn.com/entry/using-uuids-laravel-eloquent-orm/ ? – Tom Regner Oct 23 '15 at 14:42
  • 2
    Str::random(6); in laravel only... – elad gasner May 08 '18 at 09:41
  • For the Googler's of the future looking for a laravel only solution. I created this model method which utilises Laravel helpers and checks the DB for existence. In this case it's for API key generation - `public function generateApiKey() { do { // generate our new API key $key = 'key_' . str_random(32); } while (static::where('api_key', $key)->exists()); // return our newly generated API key return $key; }` – Chris Oct 11 '18 at 11:52

3 Answers3

28

You can use :

sha1(time())

Explanation: sha1 is hash function, and most important characteristic of hash function is that they never produce the same hash of different string, so as time() is always unique in theory sha1(time()) will always give you unique string with fixed width.

EDITED:

You can use you function but before giving token you can connect to database and check if token exists, if exists generate new token, if not exists give hin this token. This mechanism will give you unique tokens.

fico7489
  • 7,931
  • 7
  • 55
  • 89
  • I wouldn't want to use sha1. The goal is that an administrator would be able to search for an application by this number for query purposes. I think sha1 strings are pretty long. – Fokwa Best Oct 23 '15 at 14:47
  • I thought mt_srand() seeds the random number generator with seed so I am wondering how token can become duplicate at some point. – Fokwa Best Oct 23 '15 at 15:22
  • You could use the built in helper function: example : $token = 'rand(111,555); echo $token; – Mas Hary Mar 22 '20 at 12:25
  • This will result in duplicate strings when code runs multiple times per second. That might not be random enough for your use case – Jacques Dec 10 '20 at 11:45
  • you can always put sleep one 1 second, or if this is to much than use milliseconds and sleep 1ms – fico7489 Dec 10 '20 at 15:15
9

You could use the built in helper function:

str_random(int);

The documentation can be found: Laravel 5.1 Docs

To ensure it is unique you could always check that the name doesn't already exist and if it does rerun the function to generate a new string.

Hope that helps.

Flyingearl
  • 659
  • 4
  • 12
  • 1
    I think we are looking for a random string, not in a table this might generate an existing string as no check is made. – Someone Aug 20 '17 at 22:21
  • This seems like a much cleaner answer than the others, but I see that str_random() is deprecated in newer Laravel versions, is there an alternative function to use? – sidewinderguy Mar 08 '19 at 19:09
  • 1
    It looks like 'str_random' was a global helper that is now gone, but you can stil use \Illuminate\Support\Str::random(). – sidewinderguy Mar 08 '19 at 19:16
  • str_random exists on Laravel 5.8 – Dazzle Dec 08 '19 at 14:52
  • For latest Laravel version that is 7, you can use it like \Str::random(10); Note the first "\" its just because I didn't included the Str trait. – Tahir Afridi Jul 28 '20 at 06:41
9

With your attempt to the problem you could apply the following to ensure a unique code:

do
{
    $token = $this->getToken(6, $application_id);
    $code = 'EN'. $token . substr(strftime("%Y", time()),2);
    $user_code = User::where('user_code', $code)->get();
}
while(!empty($user_code));

Edit

To avoid an infinite loop in laravel, use

do
    {
        $token = $this->getToken(6, $application_id);
        $code = 'EN'. $token . substr(strftime("%Y", time()),2);
        $user_code = User::where('user_code', $code)->get();
    }
    while(!$user_code->isEmpty());

http://laravel.com/api/5.0/Illuminate/Support/Collection.html#method_isEmpty

or go with

  do
        {
            $token = $this->getToken(6, $application_id);
            $code = 'EN'. $token . substr(strftime("%Y", time()),2);
            $user_code = User::where('user_code', $code)->first();
        }
        while(!empty($user_code));

Instead of get(), use first(). $user_code is probably unique so we can conveniently pull out the first result.

Fokwa Best
  • 3,322
  • 6
  • 36
  • 51
user2094178
  • 9,204
  • 10
  • 41
  • 70