How to generate a random, unique, alphanumeric string? How to generate a random, unique, alphanumeric string? php php

How to generate a random, unique, alphanumeric string?


PHP 7 standard library provides the random_bytes($length) function that generate cryptographically secure pseudo-random bytes.

Example:

$bytes = random_bytes(20);var_dump(bin2hex($bytes));

The above example will output something similar to:

string(40) "5fe69c95ed70a9869d9f9af7d8400a6673bb9ce9"

More info: http://php.net/manual/en/function.random-bytes.php

PHP 5 (outdated)

I was just looking into how to solve this same problem, but I also want my function to create a token that can be used for password retrieval as well. This means that I need to limit the ability of the token to be guessed. Because uniqid is based on the time, and according to php.net "the return value is little different from microtime()", uniqid does not meet the criteria. PHP recommends using openssl_random_pseudo_bytes() instead to generate cryptographically secure tokens.

A quick, short and to the point answer is:

bin2hex(openssl_random_pseudo_bytes($bytes))

which will generate a random string of alphanumeric characters of length = $bytes * 2. Unfortunately this only has an alphabet of [a-f][0-9], but it works.


Below is the strongest function I could make that satisfies the criteria (This is an implemented version of Erik's answer).
function crypto_rand_secure($min, $max){    $range = $max - $min;    if ($range < 1) return $min; // not so random...    $log = ceil(log($range, 2));    $bytes = (int) ($log / 8) + 1; // length in bytes    $bits = (int) $log + 1; // length in bits    $filter = (int) (1 << $bits) - 1; // set all lower bits to 1    do {        $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));        $rnd = $rnd & $filter; // discard irrelevant bits    } while ($rnd > $range);    return $min + $rnd;}function getToken($length){    $token = "";    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";    $codeAlphabet.= "0123456789";    $max = strlen($codeAlphabet); // edited    for ($i=0; $i < $length; $i++) {        $token .= $codeAlphabet[crypto_rand_secure(0, $max-1)];    }    return $token;}

crypto_rand_secure($min, $max) works as a drop in replacement for rand() or mt_rand. It uses openssl_random_pseudo_bytes to help create a random number between $min and $max.

getToken($length) creates an alphabet to use within the token and then creates a string of length $length.

Source: http://us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322


Security Notice: This solution should not be used in situations where the quality of your randomness can affect the security of an application. In particular, rand() and uniqid() are not cryptographically secure random number generators. See Scott's answer for a secure alternative.

If you do not need it to be absolutely unique over time:

md5(uniqid(rand(), true))

Otherwise (given you have already determined a unique login for your user):

md5(uniqid($your_user_login, true))


Object-oriented version of the most up-voted solution

I've created an object-oriented solution based on Scott's answer:

<?phpnamespace Utils;/** * Class RandomStringGenerator * @package Utils * * Solution taken from here: * http://stackoverflow.com/a/13733588/1056679 */class RandomStringGenerator{    /** @var string */    protected $alphabet;    /** @var int */    protected $alphabetLength;    /**     * @param string $alphabet     */    public function __construct($alphabet = '')    {        if ('' !== $alphabet) {            $this->setAlphabet($alphabet);        } else {            $this->setAlphabet(                  implode(range('a', 'z'))                . implode(range('A', 'Z'))                . implode(range(0, 9))            );        }    }    /**     * @param string $alphabet     */    public function setAlphabet($alphabet)    {        $this->alphabet = $alphabet;        $this->alphabetLength = strlen($alphabet);    }    /**     * @param int $length     * @return string     */    public function generate($length)    {        $token = '';        for ($i = 0; $i < $length; $i++) {            $randomKey = $this->getRandomInteger(0, $this->alphabetLength);            $token .= $this->alphabet[$randomKey];        }        return $token;    }    /**     * @param int $min     * @param int $max     * @return int     */    protected function getRandomInteger($min, $max)    {        $range = ($max - $min);        if ($range < 0) {            // Not so random...            return $min;        }        $log = log($range, 2);        // Length in bytes.        $bytes = (int) ($log / 8) + 1;        // Length in bits.        $bits = (int) $log + 1;        // Set all lower bits to 1.        $filter = (int) (1 << $bits) - 1;        do {            $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));            // Discard irrelevant bits.            $rnd = $rnd & $filter;        } while ($rnd >= $range);        return ($min + $rnd);    }}

Usage

<?phpuse Utils\RandomStringGenerator;// Create new instance of generator class.$generator = new RandomStringGenerator;// Set token length.$tokenLength = 32;// Call method to generate random string.$token = $generator->generate($tokenLength);

Custom alphabet

You can use custom alphabet if required.Just pass a string with supported chars to the constructor or setter:

<?php$customAlphabet = '0123456789ABCDEF';// Set initial alphabet.$generator = new RandomStringGenerator($customAlphabet);// Change alphabet whenever needed.$generator->setAlphabet($customAlphabet);

Here's the output samples

SRniGU2sRQb2K1ylXKnWwZr4HrtdRgrMq1sRUjNq1K9rG905aneFzyD5IcqD4dlCI0euIWffrURLKCCJZ5PQFcNUCto6cQfDAKwPJMEM5ytgJyJyGqoD5FQwxv82YvMrduoRF6gAawNOEQRICnOUNYmStWmOpEgSsdHUkEn4565AJoTtkc8EqJ6cC4MLEHUxeVywMdYXczuZmHaJ50nIVQjOidEVkVnabaJGt7cdLDbIxMctLsEBWgAw5BByP5V0iqT0B2obq3oerbeXkDVLjZrrLheW4d8fOUQYCny6tj2TYDlTuu1KsnUyaLkeObwa

I hope it will help someone. Cheers!