Home > Enterprise >  Laravel PHP: How generate a batch of unique download codes to get a round number of 1000 of them
Laravel PHP: How generate a batch of unique download codes to get a round number of 1000 of them

Time:08-14

I am populating my DB table with unique download codes.

My intention is to make sure that at the end I will have a 1000 unique codes. So far I have this code in my controller method:

        // determining how many codes have to be generated
        $totalcount_generated_so_far = DownloadCode->count();
        $quantity = 1000 - $totalcount_generated_so_far;

        if($quantity < 0) {
            return "nothing generated! You already have more than 1000 codes.";
        }

        $object = new DownloadCode;
        for($i = 0; $i < $quantity; $i  ) {    
            $object = new DownloadCode;

                $length = 6;
                $keys = array_merge(range(1,9), range('A', 'Z'));

                $key1 = "";
                for($i=0; $i < $length; $i  ) {
                    $key1 .= $keys[mt_rand(0, count($keys) - 1)];
                }
            $object->code_download = $key1;  // a ready to use 6-digit

            $object->save(); 
        }
        return $quantity . " unique codes have been generated.";

Problem: The above code does not check if a generated code is unique.

TODO: Make the function to check if the code has been already generated (a very rare event, but still!)?

Partial solution: I could put the $object->save(); inside an if condition:

            // check for uniqueness
            $uniq_test = DownloadCode::where('code_download',$key2)->first(); 
            if($uniq_test) {
                $i--
            } else {
                $object->save(); 
            }

Is there a better solution?

Thank you.

CodePudding user response:

The problem with random numbers is that there is no way to guarantee that you can generate a certain number of them. For any value of n there is a probability, however small, that you will generate the same random number repeatedly, and thus never reach the number of different codes you need.

One answer is to use a deterministic function, but that can be predictable.

To generate a known number of random codes combine the two methods.

So, in pseudo code:

for some number of iterations
  generate a random code of some length
  append a sequential number in some range
return the list of codes.

Identical random codes will be distinguished by differing sequential suffixes, so no collision.

In PHP this would look something like this:

function makeCodes($numCodes, $codeLength) {
  // source digits
  $digits = '01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  $codes = [];
  $nextCode = 0;
  // Make a number of codes
  for ($i = 0; $i<$numCodes; $i  ) {
    $code = '';
    // Create a randomised string from the source digits
    for ($j = 0; $j<$codeLength-3;$j  ) {
        $code .= $digits[random_int(0,strlen($digits)-1)];
    }
    // Append the sequential element
    $codes[] = sprintf('%sX', $code, $nextCode);
    $nextCode  ;
  }
  return $codes;
}

print_r(makeCodes(10, 24));

Returns:

(
    [0] => BL8TKD86VW086XS3PBKZ4000
    [1] => MSBYAAPWGLROKL0NKP48L001
    [2] => XCDI783PW1J1RD9X3KM71002
    [3] => GAKZE96PVA1X6DR7X1Y4N003
    [4] => M6DCEEOMLYGC42DPD8GVY004
    [5] => 1DKFL67IZ2EA0UTEIWW61005
    [6] => XMSU0UUD9GHDAQN3XMYW5006
    [7] => 4QOKM1YOPCW2NK1E6CL9Q007
    [8] => VHMURGPH7AKR8HOEXPBAN008
    [9] => EU0L5QAGPB211WZ5VDE4R009
)

This will produce a list of ten 24-digit codes made up of a 21-digit random prefix followed by a a 3-digit hex number in the range 000 to 009

There are obviously many possible variations on this. Change the sequential range to some other starting point; change the sequential length; prepend the sequential portion; embed the sequential portion, and so on. I'm sure you can dream up something to suit your preferences.

Demo: https://3v4l.org/cboZ0

CodePudding user response:

Laravel has a helper Which generates safety unique IDs.

Generate UUID with Laravel

  • Related