I already answered such question before. And I updated my code to add more randomness (entropy) to the generated id.
This class generate pseudo-unique, non-sequential, non-numeric IDs.
class IdGenerator {
static private function _nextChar() {
return base_convert(mt_rand(0, 35), 10, 36);
}
static public function generate() {
$parts = explode('.', uniqid('', true));
$id = str_pad(base_convert($parts[0], 16, 2), 56, mt_rand(0, 1), STR_PAD_LEFT)
. str_pad(base_convert($parts[1], 10, 2), 32, mt_rand(0, 1), STR_PAD_LEFT);
$id = str_pad($id, strlen($id) + (8 - (strlen($id) % 8)), mt_rand(0, 1), STR_PAD_BOTH);
$chunks = str_split($id, 8);
$id = array();
foreach ($chunks as $key => $chunk) {
if ($key & 1) { // odd
array_unshift($id, $chunk);
} else { // even
array_push($id, $chunk);
}
}
// add random seeds
$prefix = str_pad(base_convert(mt_rand(), 10, 36), 6, self::_nextChar(), STR_PAD_BOTH);
$id = str_pad(base_convert(implode($id), 2, 36), 19, self::_nextChar(), STR_PAD_BOTH);
$suffix = str_pad(base_convert(mt_rand(), 10, 36), 6, self::_nextChar(), STR_PAD_BOTH);
return $prefix . self::_nextChar() . $id . $suffix;
}
}
If you execute this script
header('Content-type: text/plain; charset=utf-8');
for ($i=0; $i<10; $i++) {
$uid = IdGenerator::generate();
echo $uid . " = " . strlen($uid) . "\n";
}
You will get something like this :
x0i8eea3c8kw4lgudmoss4c4w03db6wl = 32
byqrfgc6hilr9d1ot4wow8gw4syugtvz = 32
ta075al22zp3v6awtlw4kgkk446mjbiv = 32
hqqa90p27e9desx99q8skokcc46fujx4 = 32
uqc000q7g20l1k9zlwko80gsow5e59e7 = 32
gxx2r5d5oa0p8iykvc4ckgc4kc0teekv = 32
ayysoos5ltfua3d0m80ccocc0kcfhqyb = 32
dtj31vi4tzmh6lhk1iccc0os4cgsze1e = 32
fvn41hh2gnk6lbrq4w0wwgko8k5ihda8 = 32
oxamsba3qh0ro6xehkw8cg400s10tiyq = 32
** Edit **
So, why all this? Why not just use uniqid()
? Because uniqid()
is sequential and is predictable. Because you need to add more entropy. This class not only use uniqid()
"more entropy" argument, it also uses mt_rand()
to pad the generated values with it. The class provided here will also always generate a 32 bytes (256-bits) string.
How random this function is? To have a duplicate ID, one would need to call uniqid()
at the exact same time, and mt_rand()
would need to return the exact same random values in the same order... seven times in a row. The bottom line is that it is quite random.
** Edit 2 **
You may also be interested by a pure PHP UUID implementation.
** Edit 3 **
The problem with using a Primary Key (PK) as unique file name is that it is predictable. If you intend to serve these files directly from URI routes, then a generated non-sequential value is safer. If you intend to serve these files otherwise, then these files will have to be assigned some unique key anyhow... and this key cannot be sequential for the exact same reasons. So, regardless the use case, having a non-sequential unique key as file name is a good idea.