This question already has answers here:
How to generate a random, unique, alphanumeric string?
(31 answers)
Closed 7 years ago.
I need to create unique id on user's every click link.
Let I have a code
<a class="popup-text" href="examplelink&aff_sub=<?php echo $up_id; ?>" data-toggle="modal">Upto Rs.10000 Cashback LED TVs
+ Get additional upto Rs. 4 Cashback from afft</a>
when user click on that link $up_id should be automatically generated. $up_id should change every time when user click on that link.
$up_id comes from following code
<?php
$up_id=md5(uniqid(rand(), true));
?>
but I am getting same id every time.
Instead of PHP you can generate random number by using javascript, tryout following code:
<a class="popup-text" href="examplelink" onclick="location.href=this.href+'?&aff_sub='+Math.floor((Math.random()*1000)+1);return false;" data-toggle="modal">Upto Rs.10000 Cashback LED TVs
+ Get additional upto Rs. 4 Cashback from afft</a>
Best solution for this would be, get current timestamp and take md5() of thst
$up_id = md5(current time stamp);
You can easily achieve this with the following function:
function random_string($length)
{
$string = "";
$chars = "abcdefghijklmanopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$size = strlen($chars);
for ($i = 0; $i < $length; $i++) {
$string .= $chars[rand(0, $size - 1)];
}
return $string;
}
Here you first generate an empty string, then you define a string with all chars you want. After you also counted the numbers of chars you can start with filling your new string. You just use a for-loop to do this. Everytime the loopcontent is called, there is one random char (from your $char) added to your empty string.
You use this function (for example if you want to store your ID in a variable) by simply typing:
$password = rand_string(15) //the number specified in brackets is the amount of characters in your password
So with this function, you can just always generate a random string (in your case, a unique ID).
Let me know, if you're experiencing any issues.
Related
I have a KMP code in PHP which is can do string matching between word to text. I wonder if i can use KMP Algorithm for string matching between text to text. Is it possible or not? and how can i use it for finding the matching of the string between 2 text.
Here's the core of KMP algorithm :
<?php
class KMP{
function KMPSearch($p,$t){
$result = array();
$pattern = str_split($p);
$text = str_split($t);
$prefix = $this->preKMP($pattern);
// print_r($prefix);
// KMP String Matching
$i = $j = 0;
$num=0;
while($j<count($text)){
while($i>-1 && $pattern[$i]!=$text[$j]){
// if it doesn't match, then uses then look at the prefix table
$i = $prefix[$i];
}
$i++;
$j++;
if($i>=count($pattern)){
// if its match, find the matches string potition
// Then use prefix table to swipe to the right.
$result[$num++]=$j-count($pattern);
$i = $prefix[$i];
}
}
return $result;
}
// Making Prefix table with preKMP function
function preKMP($pattern){
$i = 0;
$j = $prefix[0] = -1;
while($i<count($pattern)){
while($j>-1 && $pattern[$i]!=$pattern[$j]){
$j = $prefix[$j];
}
$i++;
$j++;
if(isset($pattern[$i])==isset($pattern[$j])){
$prefix[$i]=$prefix[$j];
}else{
$prefix[$i]=$j;
}
}
return $prefix;
}
}
?>
I calling this class to my index.php if i want to use to find word on the text.
This is the step that i want my code do :
(1). I input a text 1
(2). I input a text 2
(3). I want a text 1 become a pattern (every single word is in text 1 treat as pattern)
(4). I want my code can find every pattern on text 1 in text 2
(5). Last, my code can show me what the percentage of similarity.
Hope you all can help me or teach me. I've been serching for the answer everywhere but can't find it yet. At least you can teach me.
If you just need to find all words that are present in both texts, you don't any string search algorithm to do it. You can just add all words from the first text to a hash table, iterate over the second text and add the words that are in a hash table to the output list.
You can use a trie instead of a hash table if you want a linear time complexity in the worst case, but I'd get started with a hash table because it's easy to use and is likely to be good enough for practical purposes.
I wonder if there is a way in PHP to generate a unique alphanumeric(case sensitive) tokens that can be unique forever without any collision. If we derive them from the time stamp string which is 10 characters like: 1394452319, that might be possible but I am not sure if we can make the token short up to 4 characters? If not possible then 5, 6, 7 and max is 8 characters. Because I want to generate short tokens to be readable by users.
Tokens should look like: 1aYc, ZoXq, 3iU9, etc.
I don't want to show the users any sequence.
One more thing, my application will be used by more than one user, so in case two users clicked at same time to generate the token, will the PHP application generate the same token (I assume we use the timestamp to generate the token)? How can we prevent from this problem?
Thank you for your help!
this is the another function that you can use also
<?php
function generateRandomString($length = 8) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, strlen($characters) - 1)];
}
return $randomString;
}
echo generateRandomString();
?>
One approach is to have an incremental (i.e. auto_update) id that you keep hidden internally. From that, you generate a hash, representing the id to hide the sequence. The incremented id gets rid of collision problems (i.e. MySQL has an integrated solution for this).
The trick you need to use now is a random hash table consinsting of two columns, both having the values n to m but with the second column being randomized. i.e.
col1 | col2
1 | 2
2 | 4
3 | 5
4 | 1
5 | 3
if you have the randomly sorted number for your incremented number, it is easy to create a hash from that. Just think about your possible chars as numbers. You get it righgt?
Assuming you have a good algorithm for random numbers, you can make a pretty good hash table. However, there also is a way to find an algorithm, providing you with the numbers as they increase. So in this example it would give you col2 = fn(col1) so i.e. 4 = fn(2).
All you have to do is take the result and re-enginer it into a formular :D
Otherwise you have to fill the table initially.
To give you a glimpse insight into the math of it, think of a function that uses odd/even characteristics of the number and combines it with addition.
With n digits using a range of 62 possibilitys (case sensitive letters and numbers) per char you have 62^n possibilities.
For 4 digits that makes 14776336 possibilities (62^4).
Thou that might sound just wonderfull, you can imagine that having a table, prefilled with 14776336 id's is not the cleanest solution.
Still, i hope this at least leads into the right direction.
EDIT:
We started a discussion on math.stackexchange.com. IT has some additional information on how to create a function for our needs.
You can use something like following
<?php
// chars
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!##$%^&*()-+';
// convert to array
$arr = str_split($chars, 1);
// shuffle the array
shuffle($arr);
// array to chars with 8 chars
echo substr(implode('', $arr), 0, 8);
?>
You can use this function :
// RETRUN 24 digit of UNIX ID :
public function getComplexIDTicket(){ // duplicate method on Rest.php
$arrAZ1 = range('A','Z');
$arrAZ2 = range('A','Z');
$arrAZ3 = range('A','Z');
$arrs1 = range('A','Z');
$arrs2 = range('A','Z');
$arrs3 = range('A','Z');
$a1 = $arrAZ1[rand(0,25)];
$a2 = $arrAZ2[rand(0,25)];
$a3 = $arrAZ3[rand(0,25)];
$s1 = $arrs1[rand(0,25)];
$s2 = $arrs2[rand(0,25)];
$s3 = $arrs3[rand(0,25)];
$s = $s1.$s2.$s3;
$t = microtime(true);
$micro = sprintf("%07d",($t - floor($t)) * 10000000);
$id = date('ymdHis').strtoupper(dechex(substr($micro,0,7)));
$id = str_pad($id, 24, $a3.$a2.$a1.$s, STR_PAD_RIGHT);
// 151106214010 3DDBF0 L D C SM4
return $id;
}
I'm generating a 6 digit code from the following characters. These will be used to stamp on stickers.
They will be generated in batches of 10k or less (before printing) and I don't envisage there will ever be more than 1-2 million total (probably much less).
After I generate the batches of codes, I'll check the MySQL database of existing codes to ensure there are no duplicates.
// exclude problem chars: B8G6I1l0OQDS5Z2
$characters = 'ACEFHJKMNPRTUVWXY4937';
$string = '';
for ($i = 0; $i < 6; $i++) {
$string .= $characters[rand(0, strlen($characters) - 1)];
}
return $string;
Is this a solid approach to generating the code?
How many possible permutations would there be? (6 Digit code from pool of 21 characters). Sorry math isn't my strong point
21^6 = 85766121 possibilities.
Using a DB and storing used values is bad. If you want to fake randomness you can use the following:
Reduce to 19 possible numbers and make use of the fact that groups of order p^k where p is an odd prime are always cyclic.
Take the group of order 7^19, using a generator co-prime to 7^19 (I'll pick 13^11, you can choose anything not divisible by 7).
Then the following works:
$previous = 0;
function generator($previous)
{
$generator = pow(13,11);
$modulus = pow(7,19); //int might be too small
$possibleChars = "ACEFHJKMNPRTUVWXY49";
$previous = ($previous + $generator) % $modulus;
$output='';
$temp = $previous;
for($i = 0; $i < 6; $i++) {
$output += $possibleChars[$temp % 19];
$temp = $temp / 19;
}
return $output;
}
It will cycle through all possible values and look a little random unless they go digging. An even safer alternative would be multiplicative groups but I forget my math already :(
There is a lot of possible combination with or without repetition so your logic would be sufficient
Collision would be frequent because you are using rand see str_shuffle and randomness.
Change rand to mt_rand
Use fast storage like memcached or redis not MySQL when checking
Total Possibility
21 ^ 6 = 85,766,121
85,766,121 should be ok , To add database to this generation try:
Example
$prifix = "stamp.";
$cache = new Memcache();
$cache->addserver("127.0.0.1");
$stamp = myRand(6);
while($cache->get($prifix . $stamp)) {
$stamp = myRand(6);
}
echo $stamp;
Function Used
function myRand($no, $str = "", $chr = 'ACEFHJKMNPRTUVWXY4937') {
$length = strlen($chr);
while($no --) {
$str .= $chr{mt_rand(0, $length- 1)};
}
return $str;
}
as Baba said generating a string on the fly will result in tons of collisions. the closer you will go to 80 millions already generated ones the harder it will became to get an available string
another solution could be to generate all possible combinations once, and store each of them in the database already, with some boolean column field that marks if a row/token is already used or not
then to get one of them
SELECT * FROM tokens WHERE tokenIsUsed = 0 ORDER BY RAND() LIMIT 0,1
and then mark it as already used
UPDATE tokens SET tokenIsUsed = 1 WHERE token = ...
You would have 21 ^ 6 codes = 85 766 121 ~ 85.8 million codes!
To generate them all (which would take some time), look at the selected answer to this question: algorithm that will take numbers or words and find all possible combinations.
I had the same problem, and I found very impressive open source solution:
http://www.hashids.org/php/
You can take and use it, also it's worth it to look in it's source code to understand what's happening under the hood.
Or... you can encode username+datetime in md5 and save to database, this for sure will generate an unique code ;)
General Overview:
The function below spits out a random ID. I'm using this to provide a confirmation alias to identify a record. However, I've had to check for collision(however unlikely), because we are only using a five digit length. With the allowed characters listed below, it comes out to about 33 million plus combinations. Eventually we will get to five million or so records so collision becomes an issue.
The Problem:
Checking for dupe aliases is inefficient and resource heavy. Five million records is a lot to search through. Especially when this search is being conducted concurrently by different users.
My Question:
Is there a way to 'auto increment' the combinations allowed by this function? Meaning I only have to search for the last record's alias and move on to the next combination?
Acknowledged Limitations:
I realize the code would be vastly different than the function below. I also realize that mysql has an auto increment feature for numerical IDs, but the project is requiring a five digit alias with the allowed characters of '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'. My hands are tied on that issue.
My Current Function:
public function random_id_gen($length)
{
$characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
$max = strlen($characters) - 1;
$string = '';
for ($i = 0; $i < $length; $i++) {
$string .= $characters[mt_rand(0, $max)];
}
return $string;
}
Why not just create a unique index on the alias column?
CREATE UNIQUE INDEX uniq_alias ON MyTable(alias);
at which point you can try your insert/update and if it returns an error, generate a new alias and try again.
What you really need to do is convert from base 10 to base strlen($characters).
PHP comes with a built in base_convert function, but it doesn't do exactly what you want as it will use the numbers zero, one and the letter 'o', which you don't have in your version. So you'll need a function to map the values from base_convert from/to your values:
function map_basing($number, $from_characters, $to_characters) {
if ( strlen($from_characters) != strlen($to_characters)) {
// ERROR!
}
$mapped = '';
foreach( $ch in $number ) {
$pos = strpos($from_characters, $ch);
if ( $pos !== false ) {
$mapped .= $to_characters[$pos];
} else {
// ERROR!
}
}
return $mapped;
}
Now that you have that:
public function next_id($last_id)
{
$my_characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
$std_characters ='0123456789abcdefghijklmnopqrstuv';
// Map from your basing to the standard basing.
$mapped = map_basing($last_id, $my_characters, $std_characters);
// Convert to base 10 integer and increment.
$intval = base_convert($mapped, strlen($my_characters), 10);
$intval++;
// Convert to standard basing, then to our custom basing.
$newval_std = base_convert($intval, 10, strlen($my_characters));
$newval = map_basing($newval_std, $std_characters, $my_characters);
return $newval;
}
Might be some syntax errors in there, but you should get the gist of it.
You could roll your own auto-increment. It would probably be fairly inefficient though as you'd have to figure out where in the process your increment was. For instance, if you assigned the position in your random string as an integer and started with (0)(0)(0)(0)(0) that would equate to 22222 as the ID. Then to get the next one, just increment the last value to (0)(0)(0)(0)(1) which would translate into 22223. If the last one gets to your string length, then make it 0 and increment the second to last, etc... It's not exactly random, but it would be incremented and unique.
I'm building a simple URL shortening script, I want to hash the URL to serve as a unique id but if I used something like MD5 the URL wouldn't be very short.
Is their some hashing functions or anyway to create a unique ID thats only 4 or 5 digits long?
Use auto incrementing integers and convert them into identifiers consisting of all letters (lower & uppercase) to shorten them:
function ShortURL($integer, $chr='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') {
// the $chr has all the characters you want to use in the url's;
$base = strlen($chr);
// number of characters = base
$string = '';
do {
// start looping through the integer and getting the remainders using the base
$remainder = $integer % $base;
// replace that remainder with the corresponding the $chr using the index
$string .= $chr[$remainder];
// reduce the integer with the remainder and divide the sum with the base
$integer = ($integer - $remainder) / $base;
} while($integer > 0);
// continue doing that until integer reaches 0;
return $string;
}
and the corresponding function to get them back to integers:
function LongURL($string, $chr='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') {
// this is just reversing everything that was done in the other function, one important thing to note is to use the same $chr as you did in the ShortURL
$array = array_flip(str_split($chr));
$base = strlen($chr);
$integer = 0;
$length = strlen($string);
for($c = 0; $c < $length; ++$c) {
$integer += $array[$string[$c]] * pow($base, $length - $c - 1);
}
return $integer;
}
Hashing will cause collisions. Just use an autoincrementing value. This includes using alphanumeric characters too to compress it. That is how most URL shortners work.
niklas's answer below is wonderfully done.
The advantage of using MD5 (or equivalent methods) is that the number of possibilities is so large that you can, for all practical purposes, assume that the value is unique. To ensure that a 4-digit random-like ID is unique would require a database to track existing IDs.
Essentially you have to repeatedly generate IDs and check against the DB.
You could always just keep the first 5 characters of a MD5 and if it already exists you add a random value to the url-string and retry until you get a unique one.
I just copied the code and ran it, and it appears that he string function are backwards. I entered the number generated in the shorturl and ran it back thought and got a different number. So I decoded the number and found the string has to be fed back into long url in reverse with the current coding above.