Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating a random and unique string

Tags:

php

unique

I need a valid way to get both a random and unique string, with either a zero (or negligible) chance of a duplicate.

I need characters in the [0-9A-z] range.

This is what I have so far:

substr(sha1(mt_rand().uniqid()),0,22);  
like image 497
Sandro Antonucci Avatar asked Feb 03 '13 16:02

Sandro Antonucci


3 Answers

Recent changes to PHP

Since I know this is actually talking about bcrypt and password salting now I can really just point people reading this to functions they should be using instead of manually rolling their own salt system.

Use password_hash($input, PASSWORD_DEFAULT); to generate a hash suitable to insert into a database. This will fetch the salt for you.

Insertion:

$hash = password_hash($_POST["password"], PASSWORD_DEFAULT, ["cost" => 16]);
DB::table("users")->insert(["username" => $user, "password" => $hash]);
// or whatever database method you use to insert data

Verification:

$hash = DB::table("users")->fetchByName($username)->select("password");
$input = $_POST["password"];

$verified = password_verify($input, $hash); // true if the password matches

In versions before PHP 5.5, use https://github.com/ircmaxell/password_compat as a drop-in1


When randomly generating a salt, the odds of a collision are

1 / [number of possible letters/numbers] ** [length]

Which for a 22-character string are impossibly low (well, not impossibly, but negligibly)

1 / (22 ** 60) = 1 / (3.51043 x 10**80)

See? tiny.


Mathematical Fallacy

If you need a truly random string (note: these strings are just a line of numbers mapped to letters), then you're a little out of luck.
What you're looking for is a CSPRNG (Cryptographically Secure Pseudo-Random Number Generator). No need for uniqueness.

As @Guarav pointed out in his answer, you can use a timestamp as your seed and then hash it. This is called a UUID (Unique Universal Identifier, if it's a 128bit timestamp) is predictable, and can be bad for a number of reasons:

  1. The accuracy to which you take this timestamp becomes the deciding factor of how predictable this salt is.
  2. If you take the time in seconds as an integer and hash it, then you end up with very defined and easily guessed salts

Nevertheless, with enough accuracy, you can still use a timestamp as a unique salt. Not random (unless you use it as a random seed and base convert it to base10, which is still a bad idea). Consider this if you can count time in something under nanoseconds and fancy using it as a unique ID. PHP cannot feasibly process fast enough to give two colliding sub-nanosecond IDs1 (but that doesn't mean you shouldn't verify!)


1: It works with composer!

like image 195
Amelia Avatar answered Oct 10 '22 09:10

Amelia


This is the way I am doing sometime...

// chars
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-+';

// convert to array
$arr = str_split($chars, 1);

// shuffle the array
shuffle($arr);

// array to chars with 22 chars
echo substr(implode('', $arr), 0, 22);

Output

xd*thKM$B#13^)9!QkD@gU

ixXYL0GEHRf+SNn#gcJIq-

$0LruRlgpjv1XS8xZq)hwY

$G-MKXf@rI3hFwT4l9)j0u

To make sure it is unique, you can always check in your database. In case it is repeated re generated the KEY.

like image 38
Madan Sapkota Avatar answered Oct 10 '22 07:10

Madan Sapkota


You can check the answer of my own question. How to generate Unique Order Id (just to show touser) with actual Order Id?

You can use TimeStamp instead of any random string.

Regarding your solution, there is possibility of collision, but its at very low level.

like image 29
Gaurav Avatar answered Oct 10 '22 07:10

Gaurav