Random string in PHP not enough characters [duplicate] - php

This question already has answers here:
Generating (pseudo)random alpha-numeric strings
(18 answers)
Closed 5 years ago.
I'm trying to make some random string in PHP with 5 letters/numbers.
It's working fine but sometimes I get a shorter string.
$characterset='ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$count=0;
$lenght=strlen($characterset);
$i=5; #number of characters
while($count < $i){
$num=rand(1,$lenght);
$letter=substr($characterset, $num, 1);
$string.=$letter;
$count++;
}
And strlen($string) is sometimes 4 (checked 100 records, 85 was 4 characters)

String characters, like arrays, start counting from zero. Run your code a bunch of times: in addition to sometimes getting not enough characters, notice how you never get an A in there?
$num = rand(0,$lenght-1); will do it.
As an alternative method, you could do this:
$max_b36 = str_repeat("Z",$number_of_characters);
$max_dec = base_convert($max_b36,36,10);
$rand_dec = rand(0,$max_dec);
$rand_b36 = base_convert($rand_dex,10,36);
$result = sprintf("%0".$number_of_characters."s",$rand_b36);
This method uses (potentially) big numbers though, so it will only support 5 characters (on 32-bit systems) or 12 characters (on 64-bit systems).

Personally I'd replace your entire logic with this one line wonder :
print $characters = substr(
str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'),
0,5)
);
(slightly off formatting so it fits on the screeen)

Thank you all for help, following code working great:
$characters='ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$string = '';
$random_string_length = 5;
$max = strlen($characters) - 1;
for ($i = 0; $i < $random_string_length; $i++) {
$string .= $characters[mt_rand(0, $max)];
}
Is it possible to avoid the same strings? I generated 50 000 records and had 48 the same.

Related

Ho do I output integers with leading zeros in PHP? [duplicate]

This question already has answers here:
Formatting a number with leading zeros in PHP [duplicate]
(11 answers)
Closed 3 years ago.
I need a little help with some PHP code. I looked at the examples for doing this with JavaScript and used that as the basis for a PHP implementation. Two issues I haven't be able to resolve. I still get a leading 1 at the start of the string. I also get fewer zeros than specified once the values have trailing zeros (i.e 10, 20, etc).
$num = 2;
$numZeros = 5;
function listRiskNumber($num, $numZeros) {
$n = abs($num);
$zeros = max(0, $numZeros - strlen(floor(json_encode($n))));
$zeroString = substr((pow(10,$zeros)),0,5);
if( $num < 0 ) {
$zeroString = '-' + $zeroString;
}
return $zeroString + $n;
}
$row = listRiskNumber($num, $numZeros);
echo $row;
I want to turn the leading 1 into a zero, and ensure trailing zeros don't get cut off. Any help would be greatly appreciated.
sprintf("%08d", $value);
Solved the problem. Thanks all for the quick answers.

PHP compare two equal strings failed

today i have a problem with two strings.
The first comes from an Function-Parameter, the second string i'm getting from a file.
I only see these characters: "703866200".
When i convert the two strings in ASCII-Chars, get this (I have the characters separated by dots):
My Function-Param: 55.48.51.56.54.54.50.48.48
String from File: 55.0.48.0.51.0.56.0.54.0.54.0.50.0.48.0.48
This means that the two strings are detected always different (strcmp).
Can anybody help me? - Is it an Encoding Problem, or what means that the second String is filled with zeros?
BTW, my string2ascii function:
function string_to_ascii($string){
$ascii = NULL;
for ($i = 0; $i < strlen($string); $i++){
$ascii .= ".".ord($string[$i]);
}
return($ascii);
}

Generating unique 6 digit code

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 ;)

PHP List all possible 6-digit numbers with specific digits [duplicate]

This question already has answers here:
Algorithm to get all possible string combinations from array up to certain length
(12 answers)
Closed 9 years ago.
How could I generate every possible number of a given amount of digits and using specific digits?
So basically, I would like to have a 6 digit number for example using only the numbers ['1','2','3']. I've tried a few methods of recursion, however, I can't get it to work correctly due to my other complication, which is adding a separator of "|" in between each 2 digits. So the list would be like so:
11|11|11
11|11|12
11|11|13
11|11|21
11|11|22
11|11|23
etc..
Would be appreciated if someone could point me in the right direction.
Also a way of dumping each of the combinations into my MySQL database would be great.
Here is a much updated answer (originally updated from this answer]1) to your question:
function findPermutations($arr, $arrLen, $size, $perArr = array(), $pos = 0, &$found = array()) {
if ($size==$pos) { //if $pos reach $size then we have found one permutation
$found[] = vsprintf("%s%s|%s%s|%s%s", $perArr);
return;
}
for ($i=0; $i<$arrLen; $i++) {
$perArr[$pos] = $arr[$i]; //put i'th char in current position
//The recursive call that move to next position with $pos+1
findPermutations($arr, $arrLen, $size, $perArr, $pos+1, $found);
}
return $found;
}
$permutations = array();
$letters = array('1','2','3');
$max_length = 6;
$permutations = findPermutations($letters, count($letters), $max_length);
for($i = 0; $i < count($permutations); $i++) {
print ($permutations[$i].'<br/>');
}
Here is what I'm doing. I'm passing in an empty array called $permutations by reference, and as I find new permutations, I'm appending them to it. When the function findPermutations() is complete, I end up with an array of all permutation, that I can iterate over or insert. To get the formatting I'm using vsprintf, that lets me pass an array of data and apply a format (in this case %s%s|%s%s|%s%s). Lastly I'm using default argument values to make calling this function cleaner.
you mean something like this?
$letters='123'; // add other numbers
for($i=0;$i<3;$i++) { //generate 3 pairs
$pairs[]=$letters[rand(0,2)] . $letters[rand(0,2)];
}
//then join them together
$finalstring=implode('-',$pairs);

How can I cram 6+31 numeric characters into 22 alphanumeric characters?

I've got a 6-digit number and a 31-digit number (e.g. "234536" & "201103231043330478311223582826") that I need to cram into the same 22-character alphanumeric field in an API using PHP. I tried converting each to base 32 (had to use a custom function as base_convert() doesn't handle big numbers well) and joining with a single-character delimiter, but that only gets me down to 26 characters. It's a REST API, so the characters need to be URI-safe.
I'd really like to do this without creating a database table cross referencing the two numbers with another reference value, if possible. Any suggestions?
Use a radix of 62 instead. That will get you 3.35 characters for the former and 17.3 characters for the latter, for an upper total of 22 characters.
>>> math.log(10**6)/math.log(62)
3.3474826039165504
>>> math.log(10**31)/math.log(62)
17.295326786902177
You can write something like pack() that works with big numbers using bc. Here is my quick solution, it converts your second number in a 13-character string. Pretty nice !
<?php
$i2 = "201103231043330478311223582826";
function pack_large($i) {
$ret = '';
while(bccomp($i, 0) !== 0) {
$mod = bcmod($i, 256);
$i = bcsub($i, $mod);
$ret .= chr($mod);
$i = bcdiv($i, 256);
}
return $ret;
}
function unpack_large($s) {
$ret = '0';
$len = strlen($s);
for($i = $len - 1; $i >= 0; --$i) {
$add = ord($s[$i]);
$ret = bcmul($ret, 256);
$ret = bcadd($ret, $add);
}
return $ret;
}
var_dump($i2);
var_dump($pack = pack_large($i2));
var_dump(unpack_large($pack));
Sample output :
string(30) "201103231043330478311223582826"
string(13) "jàÙl¹9±̉"
string(47) "201103231043330478311223582826.0000000000000000"
Since you need URL-friendly characters, use base64_encode on the packed string, this will give you a 20-character string (18 if your remove the padding).

Categories