I have a users table, the user ID is public. But I want to obfuscate the number of registered user and trends of the project, so I don't want to have public incrementing IDs.
When a new user is created I want to find a random integer number that is greater than a certain number and that is not yet in the database.
Naive code:
<?php
$found = false;
while(!$found) {
$uid = rand(1000000000,4294967295) // find random number betwen minimum and maximum
$dbh->beginTransaction();
// check if user id is in use, and if not insert it
if($dbh->query("SELECT * FROM users WHERE uid = $uid")) {
$dbh->exec("INSERT INTO users (uid) VALUES ($uid)");
$found = true;
}
$dbh->commit();
}
// we just got our new uid ...
?>
This will work it however may become inefficient. True that there is a big range and the probability of hitting an unused uid is high. But what if I want to use a smaller range, because I don't want to have so long userids?
Example of my concerns:
- 60% of all user ids are in use
- the chance of hitting an unused uid are 0.4
- the first attempt has 0.4% success rate
- if 1st not successful the second attempt has 0.6*0.4 probability
- so with a maximum of two tries i have 0.4 + 0.6*0.4 proability (is that right??)
So one method to optimize is that came to my mind is the following:
- find a random number, check if its free, if not, increment it by 1 and try again and so on
- if the maximum number is hit, continue with the minimum number
That should give me a number with a maximum runtime of O(range)
That sounds pretty bad but I think it is not, because I submit random numbers to the database and that they are all at the beginnig is very unlikely. So how good/bad is it really?
I think this would work just fine but I