1 minute read

I needed to generate a unique code, suitable for URLs and somewhat short so it doesn’t scare the user.

Doing md5(microtime()) is nice but it is 32 chars long. I could use base64, but it contains weird characters like “/” and “=”.

So how do I restrain the encoding to alphanumeric ? I found the inspiration from Ross Duggan and I added a random function. He also removes a couple ambiguous chars, which I think is a nice touch.

The choice of random could be discussed but the idea is there.

UPDATE: As suggested by a friend, it is simpler and a better use of the range of available entropy to generate each character separately. You can see the old version in the Gist.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
// CodeGenerator.php

class CodeGenerator
{
    private static $alphabet   = '23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
    private static $max_offset = 55;

    /**
     * Generate a random character of non-ambiguous number or letter.
     * @return string the character
     */
    public static function randomChar()
    {
        $index = mt_rand(0, self::$max_offset);
        return self::$alphabet[$index];
    }

    /**
     * Generate a random string of non-ambiguous numbers and letters.
     * @param $length Size of generated string
     * @return string
     * @throws InvalidArgumentException
     */
    public static function generate($length = 16)
    {
        if ($length < 1) {
            throw new InvalidArgumentException(__METHOD__ . ' expects a $length argument of at least 1, input was: ' . $length);
        }

        $random = '';

        for ($i=0; $i < $length; $i++) {
            $random .= self::randomChar();
        }

        return $random;
    }
}

View Gist

Tests included

Tags:

Updated: