Laravel str_random() or custom function?

122,106

Solution 1

str_random (Str::random()) tries to use openssl_random_pseudo_bytes which is a pseudo random number generator optimized for cryptography, not uniqueness. If openssl_random_pseudo_bytes is not available, it falls back to quickRandom():

public static function quickRandom($length = 16)
{
    $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

    return substr(str_shuffle(str_repeat($pool, 5)), 0, $length);
}

In my opinion quickRandom code is not reliable for uniqueness nor cryptography.

Yes, having openssl_random_pseudo_bytes and using 32 bytes is almost impossible to see a collision, but it's still possible. If you want to make sure your strings/numbers will be unique (99.99%), you better use a UUID function. This is what I normally use:

/**
 * 
 * Generate v4 UUID
 * 
 * Version 4 UUIDs are pseudo-random.
 */
public static function v4() 
{
    return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',

    // 32 bits for "time_low"
    mt_rand(0, 0xffff), mt_rand(0, 0xffff),

    // 16 bits for "time_mid"
    mt_rand(0, 0xffff),

    // 16 bits for "time_hi_and_version",
    // four most significant bits holds version number 4
    mt_rand(0, 0x0fff) | 0x4000,

    // 16 bits, 8 bits for "clk_seq_hi_res",
    // 8 bits for "clk_seq_low",
    // two most significant bits holds zero and one for variant DCE1.1
    mt_rand(0, 0x3fff) | 0x8000,

    // 48 bits for "node"
    mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
    );
}

It generates a VALID RFC 4211 COMPLIANT version 4 UUID.

Check this: https://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions

Solution 2

you can use this

use Illuminate\Support\Str;

$random = Str::random(40);

Solution 3

The accepted answer was true in April of 2014. It is not accurate anymore. In November of 2014 there was a commit which removed the use of quickRandom. As random_bytes became available in PHP 7 Laravel slowly shifted to that function and uses that one only without any fallback.

ramsey/uuid is the default UUID library in Laravel. By looking at the code we can find out the default random generator is RandomBytesGenerator which uses random_bytes. The same method Str::random uses.

The Wikipedia page about UUID states the following about UUID v4:

[...] version-4 UUID will have 6 predetermined variant and version bits, leaving 122 bits for the randomly generated part, [...]

https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)

128 bits = 122 random bits + 6 version bits. 128 bits is exactly 16 bytes. Most of the UUID implementations reads 16 bytes of random bytes and then replaces the version at the specified position (in case of v4).

All in all, as of now it is almost the same if you would use Str::random with length equal to 16 or Uuid::uuid4 (without modifying the randomGenerator of Uuid).

Solution 4

To make it more unique use TIMESTAMP and concat row id with it simple and zero possibility to repeat number

Solution 5

You can use this package.

For example:

Uuid::generate()
Share:
122,106
Michael
Author by

Michael

LinkedIn | Twitter | GitHub

Updated on July 08, 2022

Comments

  • Michael
    Michael almost 2 years

    Is the Laravel str_random() function random enough so that I can use it for IDs?

    For example:

    str_random(32);
    

    This produces a random string of length 32 made up of alphanumeric characters [a-zA-z0-9] (62 characters in total).

    Which equates to 2272657884496751345355241563627544170162852933518655225856 possibilities.

    However, my question is, is this going to be good enough? Or should I consider using UUIDs or another custom function.

  • Michael
    Michael about 10 years
    Where you state 'if it is available' with respect to openssl, why wouldn't it be? Also, what is the best method for uniqueness as I will be using the strings as IDs.
  • Antonio Carlos Ribeiro
    Antonio Carlos Ribeiro about 10 years
    In this line: github.com/laravel/framework/blob/master/src/Illuminate/Supp‌​ort/…, Taylor check if it's available, so I have to presume it might not always be.
  • Michael
    Michael about 10 years
    In your opinion, would quickRandom suffice? if I were to check that it is of course unique before I save it. Chances of two collisions occurring consecutively are very slim...?
  • Antonio Carlos Ribeiro
    Antonio Carlos Ribeiro about 10 years
    It's not. It may be good for temporary file creation/deletion, or to provide html unique id on pages, to give some examples, but not to be used as id. Edited to make it clearer.
  • Michael
    Michael about 10 years
    Just to be sure then, is it ok to use UUID as an ID within a database rather than a standard auto-incrementing integer?
  • Antonio Carlos Ribeiro
    Antonio Carlos Ribeiro about 10 years
    There's no 100% safety in this case, I think it's very safe but I would still try catch (the save(), create() or update()) and generate a new UUID in case of collision.
  • Michael
    Michael about 10 years
    Thank you, I will look into implementing the UUID as ID, also adding try-catch when dealing with the DB.
  • Sam Dark
    Sam Dark over 8 years
    There was a bug in PHP implementation of OpenSSL giving tons of collisions which is fixed in the following versions: >= 5.4.44, >= 5.5.28, >= 5.6.13, >= 7.0.0
  • Stephen RC
    Stephen RC almost 8 years
    For your UUID, all you're doing is generating a really long random number based entirely off mt_rand(). It'd be no different from doing mt_rand($largeNumber, $largerNumber)... you're just adding some dashes to make it look less like a really long number.
  • Mohamed Raza
    Mohamed Raza almost 3 years
    which was worked on laravel 8. you are welcome