I want to generate unique identificator in following 12 numeric format:
YYYYMMDDXXXX
Example:
201403052318
Where:
YYYYMMDD is a current date value and other XXXX is randomly generated value.
$today = date("Ymd");
$rand = sprintf("%04d", rand(0,9999));
$unique = $today . $rand;
Daily required unique volume is about 100. What methods using PHP should I use to prevent possible duplicates in rand values or make all id maximum unique? Maybe possible use current time functions to compact these numbers in last 4 characters?
EDITED:
Unique value connected to MySQL database as prime index of table. It is initial values not connected to any stored information in database.
You can't rely on rand() , There is a possibility you will generate a duplicate (Pretty rare for a rand(0,9999) to generate a duplicate, but that will at some point).
So instead of going for rand(), just create an incremental value (say.. starting from 1) and append to your generated date.
Next time when you regenerate a new id, grab that incremental value's (say if you had stored it somewhere.. must be 1 right ?) status, increment it and append it to your new date.
Not an ideal solution.. (Critics welcome)
You can make use of a uniqid coupled with sha-1 and time and do a substr() on them for first 4 chars.
<?php
$today = date("Ymd");
$rand = strtoupper(substr(uniqid(sha1(time())),0,4));
echo $unique = $today . $rand;
OUTPUT :
201403094B3F
I needed to do something similar, a solution that would keep time and also keep the id unique and i ended up with a solution to use PHP function time() like this
$reference_number = 'BFF-' . time(); you can change the BFF to something that makes more sense to your business logic.
My unique reference id looks like BFF-1393327176 and the number can be converted from Unix to real time which will give you, Tue, 25 Feb 2014 11:19:36
I hope this helps
If the unique values generated once, you just need to make conditional choice for the rand value and store the value in an array which is going to be the condition -using inarray-:
$amount = 100; // the amount of ids
$previousValues = array();
for ($i = 0; $i < $amount; $i++){
$rand = rand(0,9999);
while (in_array($rand, $previousValues)){
$rand = rand(0, 9999);
}
$previousValues[] = $rand;
$today = date("Ymd");
$unique = $today.$rand;
echo $unique."\n";
}
Checkout this demo.
A possible solution for creating unique "Unique Order Number" is following, I assume that you have orders table and field order_number, then the code is:
$orderNumber = DB::table('orders')->max('order_number') + random_int(10, 100);
If first order number is inserted as "100000000000" that method will give you this numbers:
100000000025
100000000056
100000000089
100000000123
100000000199
100000000232
100000000249
with that approach there is no possibility for non-unique number, but cons is that each number is greater the previous (not 100% random) but that approach is acceptable for most of the cases.
Related
I am generating random numbers using php random function, but I want the generated number should be unique and it should not be repeated again.
----------
php code
$number = rand(100,100000); //a six digit random number between 100 to 100000
echo $number;
----------
but I am using this function for multiple times in my code for users so at very rare case there should be a chance of generating same number again. how can i avoid that.
I would do this:
You said you have branches. The receipt id could look something like this:
$dateString = date('Ymd'); //Generate a datestring.
$branchNumber = 101; //Get the branch number somehow.
$receiptNumber = 1; //You will query the last receipt in your database
//and get the last $receiptNumber for that branch and add 1 to it.;
if($receiptNumber < 9999) {
$receiptNumber = $receiptNumber + 1;
}else{
$receiptNumber = 1;
}
Update the receipt database with the receipt number.
$dateString . '-' . $branchNumber . '-' . $receiptNumber;
This will read:
20180406-101-1
This will be unique(Provided you do less than 10,000 transactions a day.) and will show your employees easily readable information.
If you are storing users in DB you should create column [ID] as primary key with auto increment and that would be best solution.
In other case I'd recommend you to simply store all user id's in ascending order from N to M by reading last ID and adding 1 to it because I see no real gain from random order that only adds complexity to your code.
There are many ways, example:
$freq = [];
$number = rand(100,100000);
$times = 10;
while($times-- > 0)
{
while(in_array($number, $freq))$number = rand(100,100000);
$freq[] = $number;
echo $number . "<br>";
}
This will print 10 random unique numbers.
random_int
(PHP 7)
<?php
$number = random_int(100, 100000);
echo $number;
All you need to do is use timestamp in php as timestamp never cross each other hence it will always generate unique number.You can use time() function in php.
The time() function is used to format the timestamp into a human desired format. The timestamp is the number of seconds between the current time and 1st January, 1970 00:00:00 GMT. It is also known as the UNIX timestamp.
<?php
$t=time();
echo $t;
?>
Also you add a rand() function and insert it in front of the $t to make it more random as if few users work at same time then the timestamp might collide.
<?php
$number = rand(100,100000);
$t=time();
$random = $number.''.$t;
echo $random;
?>
The above will reduce the chance to timestamp collide hence making the probability of number uniqueness almost 100%.
And if you make your column unique in your database then the php wont insert the number hence this bottleneck will ensure you will always get a unique random number.
bill_id not null unique
If you are using it for something like user id, then you can use uniqid for that. This command gets a prefixed unique identifier based on the current time in microseconds.
Here's how to use it:
string uniqid ([ string $prefix = "" [, bool $more_entropy = FALSE]] )
Where prefix is used if you are generating ids for a lot if hosts at the same time, you can use this to differentiate between various hosts if id is generated at the same microsecond.
more_entropy increases the likeness of getting unique values.
Usage:
<?php
/* A uniqid, like: 4b3403665fea6 */
printf("uniqid(): %s\r\n", uniqid());
/* We can also prefix the uniqid, this the same as
* doing:
*
* $uniqid = $prefix . uniqid();
* $uniqid = uniqid($prefix);
*/
printf("uniqid('php_'): %s\r\n", uniqid('php_'));
/* We can also activate the more_entropy parameter, which is
* required on some systems, like Cygwin. This makes uniqid()
* produce a value like: 4b340550242239.64159797
*/
printf("uniqid('', true): %s\r\n", uniqid('', true));
?>
this code must work
some description about code:
generate unique id
extract numbers form unique id with regex
gathering numbers from regex with a loop
<?php
$unique = uniqid("",true);
preg_match_all("!\d+!", $unique ,$matches);
print_r($matches);
$numbers = "";
foreach($matches[0] as $key => $num){
$numbers .= $num;
}
echo $numbers;
I want to create user accounts with a public_id which is always a unique, integer random (not incremental) value.
I can use loops to check if the random integer is unique, but that doesn't seem like a really nice solution.
I found some alphabetic-numeric generators, and I guess I could convert them to integers using some string to integer converter, but are there an integer -specific ways?
I also worry about possible collisions, but it looks like the chance will be always there in a long run.(?)
You can either use one of native php functions like mt_rand or use more reliably way - generating integer based on microtime function.
To ensure that the value is unique you need to add a unique index on a column in DB and write 'ON DUPLICATE UPDATE' to insert/update queries which will add some digits to the value if it is not unique
There are 2 possible solutions:
1) If your "long run" is really really long - it means this is
possible, that you are out of PHP_INT_MAX and there is no
only-integer-specific way.
2) If you are not out of PHP_INT_MAX - then you need some storage for
checking the ids.
In case of 1 you can use library hashids. To avoid collisions - you'll need some incremental counter on input. Then you can convert strings by each letter back to integer.
In case of 2 - you can use some in-memory database like redis for performance.
Using timeStamp will really do a great job since it uses time to generate it random numbers .you can also concatenate the below function with other random generated numbers.
function passkey($format = 'u', $utimestamp = null){
if (is_null($utimestamp)) {
$utimestamp = microtime(true);
}
$timestamp = floor($utimestamp);
$milliseconds = round(($utimestamp - $timestamp) * 1000000);
return date(preg_replace('`(?<!\\\\)u`', $milliseconds, $format),$timestamp);
}
echo passkey(); // 728362
You can use a linear congruential generator with a large period.
Here is one that generates unique integers which always have 6 digits. It will not generate duplicates until it has generated all numbers between 100000 and 996722, which gives you almost 900 000 different numbers.
The condition is that you can provide the function the number it last generated. So if you store the number in the database, you have to somehow retrieve the last assigned one, so you can feed it to this function:
function random_id($prev) {
return 100000 + (($prev-100000)*97 + 356563) % 896723;
}
$prev = 100000; // must be a 6 digit number: the initial seed.
// Generate the first 10 pseudo-random integers.
for ($i = 0; $i < 10; $i++) {
$prev = random_id($prev);
echo $prev . "\n";
}
The above generation of the first 10 numbers yields:
456563
967700
331501
494085
123719
963860
855744
232445
749606
697735
You can do this for other ranges by following the rules in the referenced article on getting a full period in linear congruential generators. Concretely, if you want to generate numbers with n digits, where the first digit cannot be zero (so between 10n-1 and 10n-1), then I find it easiest to find a large prime just below 9⋅10n-1 to serve as the last number of the formula. The other two numbers can then be any positive integer, but better keep the first one small to avoid overflow.
However, PHP integers are limited to PHP_INT_MAX (typically 2147483647), so for numbers with 10 or more digits you will need to use floating point operators. The % operator should not be used then. Use fmod instead.
For example, to generate numbers with 12 digits, you could use this formula:
function random_id($prev) {
return 100000000000 + fmod((($prev-100000000000)*97 + 344980016453), 899999999981);
}
$prev = 100000000000; // must be a 12 digit number: the initial seed.
// Generate the first 10 pseudo-random integers.
for ($i = 0; $i < 10; $i++) {
$prev = random_id($prev);
echo $prev . "\n";
}
I have a piece of code which will select x number of days into the future and print it out.
I'm then trying to select data from those timestamps, and print out accordingly:
Below I am selecting the number of days in the future it should loop ($max) and how many rows/data there is ($data["cnt"])
$stmt=$dbh->prepare("select round((expire - unix_timestamp()) / 86400) as days, count(*) as cnt from xeon_users_rented WHERE user_by=:username group by days;");
$stmt->bindParam(":username",$userdata['username']);
$stmt->execute();
$data=$stmt->fetchAll();
$max = max(array_map(function($d){
return $d['days'];
}, $data));
$expireData = array();
I then loop through x number of days in the future and print it out: (Let's say that $x is = 10)
for($x = 0; $x <= $max; $x++){
if ($data[$x]["cnt"] > 0){
$expireData[] = $data[$x]["cnt"];
}else{
$expireData[] = 0;
}
$stamp = strtotime('+'.$x.' day', time());
$expireDays[] = date("Y/m/d", $stamp);
}
I then print out the days data and the data:
<?php echo implode("', '", $expireDays); ?>
<?php echo implode("', '", $expireData); ?>
Which gives me:
'2014/11/05', '2014/11/06', '2014/11/07', '2014/11/08', '2014/11/09', '2014/11/10', '2014/11/11', '2014/11/12', '2014/11/13', '2014/11/14', '2014/11/15'
and (where each digit represent a value for that specific date)
2,8,0,0,0,0,0,0,0,0
So far so good. The only problem here is, that the data (2,8,0,0etc.) is not correct. It should for example be:
0,0,2,0,0,0,8,0,0,0
My question is: How can I print out the data, where it matches the timestamp (xeon_users_rented.expire)?
To simplify my answer from before and to answer your question directly "How can I print out the data, where it matches the timestamp"?
You need to first put the unix timestamp of "strtotime('+'.$x.' day', time());" into an array from your original loop. Remove the expiredays[] stuff from that loop.
Then loop through that array and then use array_search for finding any matching indexes in the $data array.
if (found in $data array)
$expireDays[] = $data[array_search position]['cnt'];
else
$expireDays[] = 0;
From what I have gathered in what you are trying to establish, the sql query (for example) returns an array such as:
$data = array(
array("days"=>232975857, "cnt"=> 4),
array("days"=>232975867, "cnt"=> 10),
array("days"=>232976689, "cnt"=> 0),
array("days"=>232976688, "cnt"=> 2)
);
The max in your case is 10. However, please note that your code (below):
$max = max(array_map(function($d){
return $d['days'];
}, $data));
could return a lot of PHP E_NOTICE errors and be slow because you are working out a maximum from the unix_timestamp at that stage which is for example 232975867 (far too many loops I suspect that you need). The max should be worked out in the following way I suspect:
$max = count($data);
In my case (from my data example example) this will return something like 4 for which your for loop code will need to reference "<" not "<=". To optimise this I would actually put straight into the for loop "...; $x < count($data); ...;" unless of course you need the $max later.
Here is a big issue for me. I don't see where currently you have any correlation between the $stamp variable and the "days" column from your sql statement. Perhaps I have not seen enough information from you to fully understand or I am interpreting your question incorrectly but your sql for one will not necessarily return the same dates as the stamp variable will calculate and will not certainly return a cnt of 0 for any dates that do not exist in that table. This is why:
if ($data[$x]["cnt"] > 0){
part of the section is unnecessary and possibly incorrect.
To answer your question why do you get "2,8,0,0,0,0...." instead of the order you expected is because the sql does not return 0 cnt values as quite simply the date does not exist in it's table and your implode still returns '0's appended as you forcibly added the 0's afterwords with the line:
$expireData[] = 0;
First of all, you need to fill your data (or re-write your data to contain cnt of '0's in the correct array places). You can achieve this from the sql level with a subquery that ensures missing dates are contained and then a cnt value of 0 is enforced. I'll leave this to you to work out however another way (via PHP) is to do the following (pseudo code):
place each 'stamps' (in unix format) in array from previous loop
forloop $i through $stamps
array_search $stamps against $data['days']
if (found)
$expireDays[] = $data[array_search position]['cnt'];
else
$expireDays[] = 0;
This means that you remove the $expireDays from your first loop.
Finally, perhaps I have misunderstood and that your 'days' column shouldn't match your $stamp dates as those dates are in the future and your 'days' columns are in the past. In this case, your only option is to adjust your sql statement to forcibly include dates that are missing (between a certain date range)
Good luck.
Background;
to create a dropdown menu for a fun gambling game (Students can 'bet' how much that they are right) within a form.
Variables;
$balance
Students begin with £3 and play on the £10 table
$table(there is a;
£10 table, with a range of 1,2,3 etc to 10.
£100 table with a range of 10,20,30 etc to 100.
£1,000 table with a range of 100, 200, 300, 400 etc to 1000.)
I have assigned $table to equal number of zeros on max value,
eg $table = 2; for the £100 table
Limitations;
I only want the drop down menu to offer the highest 12 possible values (this could include the table below -IMP!).
Students are NOT automatically allowed to play on the 'next' table.
resources;
an array of possible values;
$a = array(1,2,3,4,5,6,7,8,9,10,20,30,40,50,60,70,80,90,10,20,30,40,50,60,70,80,90,100,200,300,400,500,600,700,800,900,1000);
I can write a way to restrict the array by table;
(the maximum key for any table is (9*$table) )//hence why i use the zeroes above (the real game goes to $1 billion!)
$arrayMaxPos = (9*$table);
$maxbyTable = array_slice($a, 0, $arrayMaxPos);
Now I need a way to make sure no VALUE in the $maxbyTable is greater than $balance.
to create a $maxBet array of all allowed bets.
THIS IS WHERE I'M STUCK!
(I would then perform "array_slice($maxBet, -12);" to present only the highest 12 in the dropdown)
EDIT - I'd prefer to NOT have to use array walk because it seems unnecessary when I know where i want the array to end.
SECOND EDIT Apologies I realised that there is a way to mathematically ascertain which KEY maps to the highest possible bid.
It would be as follows
$integerLength = strlen($balance);//number of digits in $balance
$firstDigit = substr($balance, 0, 1);
then with some trickery because of this particular pattern
$maxKeyValue = (($integerlength*9) - 10 + $firstDigit);
So for example;
$balance = 792;
$maxKeyValue = ((3*9) - 10 + 7);// (key[24] = 700)
This though works on this problem and does not solve my programming problem.
Optional!
First of all, assuming the same rule applies, you don't need the $a array to know what prices are allowed on table $n
$table = $n; //$n being an integer
for ($i = 1; $i <= 10; $i++) {
$a[] = $i * pow(10, $n);
}
Will generate a perfectly valid array (where table #1 is 1-10, table #2 is 10-100 etc).
As for slicing it according to value, use a foreach loop and generate a new array, then stop when you hit the limit.
foreach ($a as $value) {
if ($value > $balance) { break; }
$allowedByTable[] = $value;
}
This will leave you with an array $allowedByTable that only has the possible bets which are lower then the user's current balance.
Important note
Even though you set what you think is right as options, never trust the user input and always validate the input on the server side. It's fairly trivial for someone to change the value in the combobox using DOM manipulation and bet on sums he's not supposed to have. Always check that the input you're getting is what you expect it to be!
Is there is any way to avoid duplication in random number generation .
I want to create a random number for a special purpose. But it's should be a unique value. I don't know how to avoid duplicate random number
ie, First i got the random number like 1892990070. i have created a folder named that random number(1892990070). My purpose is I will never get that number in future. I it so i have duplicate random number in my folder.
A random series of number can always have repeated numbers. You have to keep a record of which numbers are already used so you can regenerate the number if it's already used. Like this:
$used = array(); //Initialize the record array. This should only be done once.
//Do like this to draw a number:
do {
$random = rand(0, 2000);
}while(in_array($random, $used));
$used[] = $random; //Save $random into to $used array
My example above will of course only work across a single page load. If it should be static across page loads you'll have to use either sessions (for a single user) or some sort of database (if it should be unique to all users), but the logic is the same.
You can write a wrapper for mt_rand which remembers all the random number generated before.
function my_rand() {
static $seen = array();
do{
$rand = mt_rand();
}while(isset($seen[$rand]));
$seen[$rand] = 1;
return $rand;
}
The ideas to remember previously generated numbers and create new ones is a useful general solution when duplicates are a problem.
But are you sure an eventual duplicate is really a problem? Consider rolling dice. Sometimes they repeat the same value, even in two sequential throws. No one considers that a problem.
If you have a controlled need for a choosing random number—say like shuffling a deck of cards—there are several approaches. (I see there are several recently posted answer to that.)
Another approach is to use the numbers 0, 1, 2, ..., n and modify them in some way, like a Gray Code encoding or exclusive ORing by a constant bit pattern.
For what purpose are you generating the random number? If you are doing something that generates random "picks" of a finite set, like shuffling a deck of cards using a random-number function, then it's easiest to put the set into an array:
$set = array('one', 'two', 'three');
$random_set = array();
while (count($set)) {
# generate a random index into $set
$picked_idx = random(0, count($set) - 1);
# copy the value out
$random_set []= $set[$picked_idx];
# remove the value from the original set
array_splice($set, $picked_idx, 1);
}
If you are generating unique keys for things, you may need to hash them:
# hold onto the random values we've picked
$already_picked = array();
do {
$new_pick = rand();
# loop until we know we don't have a value that's been picked before
} while (array_key_exists($new_pick, $already_picked));
$already_picked[$new_pick] = 1;
This will generate a string with one occurence of each digit:
$randomcharacters = '0123456789';
$length = 5;
$newcharacters = str_shuffle($randomcharacters);
$randomstring = substr($newcharacters, 0, $length);