How do I make sure that the password contains at least one character from each array? I could use do..while, right? What I don't quite understand is what I will need to put in the if statement inside do...while.
Is do...while the only way to ensure at least one character from each array is in the final password or are there other ways?
$length = 6;
$a1 = str_split('0123456789');
$a2 = str_split('%^*+~?!');
$a3 = str_split('abcdefghigklmnopqrstuvwxyz');
$result = ""; //final random password
for($i = 0; $i < $length; $i++){
$values = [$a1,$a2,$a3];
$chosen = array_rand($values);
$result .= $values[$chosen][array_rand($values[$chosen])];
}
echo $result;
$length = 6;
$a1 = str_split('0123456789');
$a2 = str_split('%^*+~?!');
$a3 = str_split('abcdefghigklmnopqrstuvwxyz');
$resultArr[] = $a1[array_rand($a1)];
$resultArr[] = $a2[array_rand($a2)];
$resultArr[] = $a3[array_rand($a3)];
for($i = 0; $i < $length-3; $i++){
$values = [$a1,$a2,$a3];
$chosen = array_rand($values);
$resultArr[] = $values[$chosen][array_rand($values[$chosen])];
}
shuffle($resultArr);
$result = implode($resultArr); //final random password
echo $result;
You can surround the for wit ha do..while and in the condition check with preg_match() and a regex pattern that checks if at least one character is in the result:
<?php
$length = 6;
$a1 = str_split('0123456789');
$a2 = str_split('%^*+~?!');
$a3 = str_split('abcdefghigklmnopqrstuvwxyz');
$result = ""; //final random password
do {
for($i = 0; $i < $length; $i++){
$values = [$a1,$a2,$a3];
$chosen = array_rand($values);
$result .= $values[$chosen][array_rand($values[$chosen])];
}
} while(!(preg_match('/^(?=.*?[0-9])(?=.*?[a-z])(?=.*?[%*+?!]).{1,}/', $result)));
echo $result;
If the there's no coincidences with the pattern using preg_match, then will return false, in the do..while condition we check if one preg_match is false, if it is, do it again.
I made my answer general for any number of arrays.
I would use preg_match() for this, but for the question you asked, yes, you need to check each array separately:
$user_inputted_password = $_POST['user_inputted_password'];
$length = strlen($user_inputted_password); // user input password - you are capturing this somewhere, right
$a1 = str_split('0123456789');
$a2 = str_split('%^*+~?!');
$a3 = str_split('abcdefghigklmnopqrstuvwxyz');
$validate = array();
$result = ""; //final random password
function populate_validation_array($match_num, &$validate) {
if (!in_array($match_num, $validate)) {
$validate[] = $match_num;
}
}
$numeric_indexes = array(1, 2, 3);
$index_count = count($numeric_indexes);
for($i = 0; $i < $length; $i++){
for($j = 0; $j < $index_count; $j++) {
$numeric_index = $numeric_indexes[$j];
if (in_array($user_inputted_password[$i], ${"a" . $numeric_index})) {
populate_validation_array($numeric_index, $validate);
}
}
}
if (count($validate) === $index_count) {
$values = array();
for($i = 0; $i < $index_count; $i++) {
$values[] = ${"a" . ($i + 1)};
}
$chosen = array_rand($values);
$result .= $values[$chosen][array_rand($values[$chosen])];
}
echo $result;
Related
I have a string composed by many letters, at some point, one letter from a group can be used and this is represented by letters enclosed in []. I need to expand these letters into its actual strings.
From this:
$str = 'ABCCDF[GH]IJJ[KLM]'
To this:
$sub[0] = 'ABCCDFGIJJK';
$sub[1] = 'ABCCDFHIJJK';
$sub[2] = 'ABCCDFGIJJL';
$sub[3] = 'ABCCDFHIJJL';
$sub[4] = 'ABCCDFGIJJM';
$sub[5] = 'ABCCDFHIJJM';
UPDATE:
Thanks to #Barmar for the very valuable suggestions.
My final solution is:
$str = '[GH]DF[IK]TF[ADF]';
function parseString(string $str) : array
{
$i = 0;
$is_group = false;
$sub = array();
$chars = preg_split('//', $str, -1, PREG_SPLIT_NO_EMPTY);
foreach ($chars as $key => $value)
{
if(ctype_alpha($value))
{
if($is_group){
$sub[$i][] = $value;
} else {
if(!isset($sub[$i][0])){
$sub[$i][0] = $value;
} else {
$sub[$i][0] .= $value;
}
}
} else {
$is_group = !$is_group;
++$i;
}
}
return $sub;
}
The recommended function for combinations is (check the related post):
function array_cartesian_product($arrays)
{
$result = array();
$arrays = array_values($arrays);
$sizeIn = sizeof($arrays);
$size = $sizeIn > 0 ? 1 : 0;
foreach ($arrays as $array)
$size = $size * sizeof($array);
for ($i = 0; $i < $size; $i++) {
$result[$i] = array();
for ($j = 0; $j < $sizeIn; $j++)
array_push($result[$i], current($arrays[$j]));
for ($j = ($sizeIn - 1); $j >= 0; $j--) {
if (next($arrays[$j]))
break;
elseif (isset($arrays[$j]))
reset($arrays[$j]);
}
}
return $result;
}
Check the solution with:
$combinations = array_cartesian_product(parseString($str));
$sub = array_map('implode', $combinations);
var_dump($sub);
Convert your string into a 2-dimensional array. The parts outside brackets become single-element arrays, while each bracketed trings becomes an array of single characters. So your string would become:
$array =
array(array('ABCCDF'),
array('G', 'H', 'I'),
array('IJJ'),
array('K', 'L', 'M'));
Then you just need to compute all the combinations of those arrays; use one of the answers at How to generate in PHP all combinations of items in multiple arrays. Finally, you concatenate each of the resulting arrays with implode to get an array of strings.
$combinations = combinations($array);
$sub = array_map('implode', $combinations);
I'm having the problem that i want to echo the class $password as often, as the number of $intcount is. Can you give me any idea how I would do that?
f.e. that I echo 4 random words if $intcount is 4, 5 words if its 5 etc etc.
<?php
$csv = array_map('str_getcsv', file('gen.csv'));
$count = $_GET['count'];
$intcount = (int)$count;
$min = 0;
$max = 4;
$rand = mt_rand( $min , $max );
$out = $csv[$rand][$rand];
$password = $out;
// var_dump($count);
// var_dump($intcount);
//
// echo $count . "\n <br>";
// echo $password * $intcount;
//
// for ($i=0; $i < $intcount ; $i++) {
// echo $password;
// }
?>
The commented code doesn't need to stay necessarily.
Thanks :)
You need to create the $rand inside the loop like:
$csv = array_map('str_getcsv', file('gen.csv'));
$count = $_GET['count'];
$intcount = (int)$count;
$min = 0;
$max = 4;
for ($i=0; $i < $intcount ; $i++)
{
$rand = mt_rand($min, $max);
$password = $csv[$rand][$rand];
echo $password;
}
Here, there is a example string "XjYAKpR" .. how to create all new string possibility with that string ??
I've tried before
function containAllRots($s, $arr) {
$n = strlen($s);
$a = array();
for ($i = 0; $i < $n ; $i++) {
$rotated = rotate(str_split($s), $i);
$a[] = $rotated;
}
print_r($a);die();
if (array_diff($arr, $a)) {
return True;
}
else
{
return False;
}
}
I make 2 function rotate and generate
function rotate($l, $n) {
$b = $l[$n];
$sisa = array_values(array_diff($l, array($b)));
for ($i = 0; $i < count($sisa) ; $i++) {
$random[] = generate($sisa, $b);
}
print_r($random);die();
$hasil = $l[$n] . implode("",$random);
return $hasil;
}
function generate($sisa, $b) {
$string = implode("",$sisa);
$length = count($sisa);
$size = strlen($string);
$str = '';
for( $i = 0; $i < $length; $i++ ) {
$str .= $string[ rand( 0, $size - 1 ) ];
}
Here there is a pair of functions that lets you calculate a permutation set
(no repetitions are taken in account)
function extends_permutation($char, $perm) {
$result = [];
$times = count($perm);
for ($i=0; $i<$times; $i++) {
$temp = $perm;
array_splice($temp, $i, 0, $char);
array_push($result, $temp);
}
array_push($result, array_merge($perm, [$char]));
return $result;
}
function extends_set_of_permutations($char, $set) {
$step = [];
foreach ($set as $perm) {
$step = array_merge($step, extends_permutation($char, $perm));
}
return $step;
}
you can use them to generate the required set of permutations. Something like this:
$seed = "XjYAKpR";
// the first set of permutations contains only the
// possible permutation of a one char string (1)
$result_set = [[$seed[0]]];
$rest = str_split(substr($seed,1));
foreach($rest as $char) {
$result_set = extends_set_of_permutations($char, $result_set);
}
$result_set = array_map('implode', $result_set);
sort($result_set);
At the end of the execution you will have the 5040 permutations generated by your string in the result_set array (sorted in alphabetical order).
Add a char and you will have more than 40000 results.
The functions are quite naive in implementation and naming, both aspects can be improved.
I found this Stack Overflow post explaining how you can generate random coupon codes.
I'm looking into using that code and generate multiple coupons at once (e.g. 50), while separate them by a comma.
The output would be: COUPON-HMECN, COUPON-UYSNC, etc.
Code below and codepad example available.
$chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$res = "COUPON-";
for ($i = 0; $i < 5; $i++) {
$res .= $chars[mt_rand(0, strlen($chars)-1)];
}
echo $res . ",";
$chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$numCodesToGenerate = 5;
for ($n = 0; $n < $numCodesToGenerate; $n++)
{
$res = "COUPON-";
for ($i = 0; $i < 5; $i++) {
$res .= $chars[mt_rand(0, strlen($chars)-1)];
}
echo $res . ",";
}
Why not use uniqid()?
$coupon_str = '';
$seperator = '';
for($i = 0; $i < 50; $i++) {
$coupon_str .= $seperator . uniqid('COUPON-');
$seperator = ',';
}
echo $coupon_str;
Output:
COUPON-502373ac95dd2,COUPON-502373ac95de8,COUPON-502373ac95ded,....
Here is a much neater version (and faster) that does what you need:
function MakeCouponCode() {
$res = "COUPON-";
for($i = 0; $i < 5; ++$i)
$res .= chr(mt_rand(0, 1) == 0 ? mt_rand(65, 90) : mt_rand(48, 57));
return $res;
}
$coupons = array();
for($i = 0; $i < 5; ++$i)
$coupons[] = MakeCouponCode();
echo implode(', ', $coupons);
Output:
COUPON-D707Y, COUPON-4B37E, COUPON-3O397, COUPON-M799X, COUPON-24Q36
You can use the coupon code generator PHP class file to generate N number of coupons and its customizable, with various options of adding own mask with own prefix and suffix. The coupon codes are separated by comma. Simple PHP coupon code generator
Example:
coupon::generate(8); // J5BST6NQ
How to convert this
$myvar = '[aaa](11,22,33,44,55)[bbb](1,2,3,4,5)';
into that
$arr_name[1] = 'aaa';
$arr_val[1] = '11,22,33,44,55';
$arr_name[2] = 'bbb';
$arr_val[2] = '1,2,3,4,5';
What functions should I use for it ?
if(preg_match_all('/\[(.*?)\]\((.*?)\)/',$myvar,$matches)) {
foreach($matches[0] as $k=>$v) {
$arr_name[$k] = $matches[1][$k];
$arr_val[$k] = $matches[2][$k];
}
}
You could try using regular expressions to extract your keys & variables, then insert them into an array:
$keys = array();
preg_match_all("/\[.+\]/", $myvar, $keys);
$values = array();
preg_match_all("/\(.+\)/", $myvar, $values);
$numKeys = count($keys);
$numVals = count($values);
$result = array();
foreach ($i = 0; $i < $numKeys; $i++) {
if ($i < $numVals) {
$result[trim($keys[$i], "[]")] = trim($values[$i], "()");
}
}