Actually in my php application i want to assign every user a unique number code. For that i am using mt_rand(0,100000000). I want it to generate millions of number for say millions of different users without repeats and save it to database. Is it possible ? Or any other technique is recommended ?
Also to make sure the number doesn't repeat I am checking if the number already exists in the db through php, if it does exist i reload the page to generate another number and save it to db orelse continue to save the number as it is.
Is it the best pratice ?
I am new to this non repeating number generator in php so don't know the efficient method.
You can use mt_getrandmax() to get the biggest value for mt_rand().
Just as the doc says,
max: Optional highest value to be returned (default: mt_getrandmax())
min max range must be within the range mt_getrandmax(). i.e. (max - min) <= mt_getrandmax() Otherwise, mt_rand() may return poorer random numbers than it should.
Related
I am developing a event organization website. Here when the user registers for an event he will be given a unique random number(10 digit), which we use to generate a barcode and mail it to him. Now,
I want to make the number unique for each registered event.
And also auto increment
One solution is to grab all the auto increment numbers in an array and generate a auto increment number using laravel takes the form (0000000001 to 9999999999) and loop through and check all the values. Grab the first value that doesn't equal to any of the values in the array and add it to the database.
But I am thinking that there might be a better solution to this. Any suggestion?
Select Maximum number stored in your DB and add 1 in it like:
SELECT (MAX(Column_Name)+1) AS Max_val FROM Table_Name;
I suggest simple timestamp-based solution using the Carbon class to produce a unique number using timestamp. It's fairly simple to have a basic unique and random stamp generation using timestamp.
You can use as given below,
use Carbon\Carbon;
$current_timestamp = Carbon::now()->timestamp; // Produces something like this 1552296328
You can use it as a unique identifier. If you want the next numbers, just +1. But keep in mind, you have to manage another number batch in a timely manner. (i.e if you have generated 500 numbers for now by increment, You should not generate another number for the next 500 seconds. Otherwise, it will repeat the number). If you want to know more, you can read here.
The solution with rand() function may not work here because it can re-produce the existing number in the database and you will be errored for Unique Constraint Violation(i.e. If you have column unique in DB).
No matter what approach you use, it would never be truly random. It will be PRNG. For your case, I think auto increment with zero fill should be enough.
But if you are set on using random number then using rand() function of PHP should be enough. 10 digit means 10000000000 unique number.Unless your project has millions of events it should realistically be no problem. So, approach 1 should be no problem. Also, you can check after generating any random number that whether that number is already present(There is 0.000001% or something like that chance.). If it is present then try to generate a random number again.
But if your project gets very successful (I.E. millions of events) then problems similar to Y2K might creep up.
MySQL UUID would give you truly unique is: Store UUID v4 in MySQL
You don’t need to worry about auto incrementing.
I have this small internal project that inserts occasional entries into a MySQL database. I have a column named "idChar" were I set it's value to a randomly generated string using 62 possible characters with a length of 31.
Today I discovered that a new entry just so happened to have the same exact idChar as an entry from several months ago. I am now checking for duplicate entries before saving them, but this made me think about the odds of this happening and I am curious to know if my implementation of generating these random keys is flawed. Getting a duplicate should be roughly 1 in 62^31 right?
function getCode($len)
{
//$len = 10;
$base='ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstwxyz123456789';
$max=strlen($base)-1;
$linkCode='';
mt_srand((double)microtime()*1000000);
while (strlen($linkCode)<$len+1)
$linkCode.=$base{mt_rand(0,$max)};
return $linkCode;
}
$idChar=getCode(30);
//code to insert into MySQL here
The odds of getting a duplicate would be calculated as per the birthday problem, because that's how you calculate the chance of collisions for the output of a function that produces a randomly chosen output from a discrete codomain. In effect you want to calculate the chance that among a pool of selections made randomly any two selections are the same.
You should also completely drop the mt_srand call as it is not necessary, and it's likely to provide worse seeds than what PHP will do automatically. Consider that the output of microtime (in my system at least) is like
0.29574400 1348356024
which means that you only have 1 million different seeds available as the last two digits of the float are always zeroes and the (double)microtime() cast completely ignores the seconds part (it would be a lousy seed anyway).
Assuming that the random number generator produces the same sequence of random numbers whenever it is seeded with the same seed then in effect you only have 1 million possible random codes instead of 62^31 -- quite a decrease! Fortunately it is documented that this does not happen on PHP 5.2.1 onwards.
If I have a truely random number and I use mt_srand to seed mt_rand with the truly random number before I use mt_rand, will this mean the result of mt_rand is now also truly random rather than pseudorandom?
In otherwords, would the below code produce a truly random integer between the given minimum and maximum value
function RandomInteger($min, $max)
{
$trueRandomNumber = GetTrueRandomNumber();
mt_srand($trueRandomNumber);
return mt_rand($min, $max);
}
Secondly, should the true random number used to seed mt_srand be of 32 integers?
Looking at your code, my guess is that you are getting some value from GetTrueRandomNumber() (code is missing) but then you want that number to be in a specific range of values. So you are taking that output and inputting it into mt_rand() because it has a method of generating a number in a specific range.
While not a direct answer to your question, a better solution is to first figure out the range of values you want (i.e. as if the input $min was 0 and $max was $max - $min). Then, figure out the maximum number of bits that are required to obtain a value in that range. Then, extract that number of bits from the output of GetTrueRandomNumber(). If the value is within the range, return the number + the original $min value. If the value isn't within the range, get more bits of data. The key is to throw away bits until you get some in the desired range.
If need example source code for this, try:
http://barebonescms.com/documentation/csprng/
You should be able to put something similar together. I'd be wary of using mt_rand() for anything like this but it might be okay in this very specific instance. It depends on what you plan on using it for. It also depends highly on how well distributed the first number from Mersenne Twister actually is. I don't think anyone's done any work on that. MT is intended to be seeded one time - who knows what the distribution pattern is for repeatedly seeding it. Also, if other code uses mt_rand(), you risk exposure of your function's state based on later values that might get generated by later mt_rand() calls.
No. Mersenne twisters are always pseudorandom. The seed only determines where in the sequence it starts.
In order to produce a unique Id I suppose I must use the uniqid function in php.
But uniqid produces a 13 digits long HEXA number, by default.
4f66835b507db
I would like to reduce this number to 7 digits long NUMERIC number but I want to conserve the unicity. Is it possible ?
4974012
This number will be used as User Id. The authentication will be done with thid Id and a password.
Some people say uniqid is not unique ! Is it a bad choice ?
Any "unique" number will eventually have a collision after generating enough records. To ensure uniqueness, you need to store the values you generated into a database and when generating next one, you need to check if there is no collision.
However, in practice, applications usually generate IDs as a simple sequence 1,2,3,... That way you know you won't get a collision until you run out of the datatype (UINT is usually 32 bits long, which gives you 4 billion unique ids).
Uniqid is not guaranteed to be unique, even in its full length.
Furthermore, uniqid is intended to be unique only locally. This means that if you create users simultaneously on two or more servers, you may end up with one ID for two different users, even if you use full-length uniqid.
My recommendations:
If you are really looking for globally unique identifiers (i.e. your application is running on multiple servers with separate databases), you should use UUIDs. These are even longer than the ones returned by uniqid, but there is no practical chance of collisions.
If you need only locally unique identifiers, stick with AUTO_INCREMENT in your database. This is (a little) faster and (a little) safer than checking if a short random ID already exists in your database.
EDIT: As it turns out in the comments below, you are looking not only for an ID for the user, but rather you are forced to provide your users with a random login name... Which is weird, but okay. In such case, you may try to use rand in a loop, until you get one that does not exist in your database.
Pseudocode:
$min = 1;
do {
$username = "user" . rand($min, $min * 10);
$min = $min * 10;
} while (user_exists($username));
// Create your user here.
Write a while loop that generates random letters and numbers of a desired length, which loops until it creates an ID that is not already in use.
Well, by reducing it to 7 characters and only numeric, you are reducing the 'uniqueness' by a lot.
I suggest using an auto increment of the user ID and start at 1000000 if it has to be 7 digits long.
If you really must generate it without auto increment, you can use mt_rand() to generate a random number 7 digits long:
$random = mt_rand(1000000, 9999999);
This is not ideal because you will need to check if the number is already in use by another user.
If you are using a Database. Define an id column as unique and auto-incremented, and then let the database manage your ids.
It's safer.
Read more : mysql-doc
Take a lookt at this article
Create short IDs with PHP - Like Youtube or TinyURL
It explains how to generate short unique ids, like youtube does.
Actually, the function in the article is very related to php function base_convert which converts a number from a base to another (but is only up to base 36).
I've seen lots of examples of how to use uniqid() in PHP to create a unique string, but need to create a unique order number (integers only, no letters).
I liked the idea of uniqid() because from what I understand it uses date/time, so the chances of having another id created that is identical is nil.... (if I'm understanding the function correctly)
mt_rand should do the trick.
It generates a random number between its first paramater and its second paramater. For example, to generate a random number between 500 and 1000, you'd do:
$number = mt_rand(500,1000);
But if you're using it as an order number, you should just use an autoincrement column. Not only is that what it's there for, but what would you do in the event where the same number was generated more than once? Assuming you're using MySQL, you can read about autoincrement columns here.
Use hexdec to convert the hex string to a number. http://us.php.net/manual/en/function.hexdec.php
hexdec(uniqid())
uniqid() does what you're thinking it does.. but if you're plugging this value into a database, you're better off using an auto incrementing field for ids.. it really depends on what you're using the ids for.
I personally use date('U') to generate a string based on the number of seconds since the UNIX EPOCH. If this isn't random enough (if you think you're going to have two orders being placed within the same exact second) simply add another layer with mt_rand(0,9):
$uniqid = date('U') . mt_rand(0,9);
This will, in almost all cases, give you an incremental ID except for the case of having orders created at exactly the same second, in which case the second order could precede the first.