I'm using a function to generate random values using TAG including parameters as Length, type of random : Alphabetic, Numeric or Mix, and LowerCase, Uppercase. Now this issue is that I want to store or save, fix or freeze, a random result to use it in multiples places. For exemple instead of RAND, I use FixRAND, then the result will be the same in the whole page as long as TAG have the same parameters.
To give you a small idea of what I already have. It's fully functional when I use some TAGs Like [RAND,10,A,U] but It generate random values every time. I need to add another TAG that can store some how the same results upon the same request.
function generateRandom($length,$type,$gen){
switch ($type) {
case 'A':
$rd= "";
srand((double)microtime()*1000000);
$data = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ";
for($i = 0; $i < $length; $i++){
$rd .= substr($data, (rand()%(strlen($data))), 1);
}
break;
case 'N':
$rd= "";
srand((double)microtime()*1000000);
$data = '0123456789';
for($i = 0; $i < $length; $i++){
$rd .= substr($data, (rand()%(strlen($data))), 1);
}
break;
case 'M':
$rd= "";
srand((double)microtime()*1000000);
$data = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789";
for($i = 0; $i < $length; $i++){
$rd .= substr($data, (rand()%(strlen($data))), 1);
}
break;
}
if ( $gen == 'U') $rd = strtoupper($rd);
if ( $gen == 'L') $rd = strtolower($rd);
return $rd;
}
$replaced_xxxxxx=str_replace("[MESSAGE]","$message",$replaced_xxxxxx);
preg_match_all("/\[RAND,[0-9]+,[AMN],[LU]\]/",$replaced_xxxxxx,$random_tag_array);
foreach ($random_tag_array[0] as $random_tag) {
$random_stripped=$random_tag;
$random_stripped=str_replace("[RAND,","",$random_stripped);
$random_stripped=str_replace("]","",$random_stripped);
$random_exploded=explode(',', $random_stripped);
$random_generated=generateRandom($random_exploded[0],$random_exploded[1],$random_exploded[2]);
$replaced_xxxxxx=preg_replace($random_tag, $random_generated, $replaced_xxxxxx,1);
Edit: As @KIKOSoftware points out, my answer was not real random. I modified my answer. This now uses random_int()
which cryptographically secure pseudo-random. The results of the random function are now saved together with the input parameters. This is the only way because random_int()
is random. This way there is no way to create the same values again so they have to be saved.
This solution takes more memory because it needs to save more values. But this one is random. You may choose between both solutions. If you are trying to get random examples the original solution is enough. For things that need to be secure (e.g. password handling ect.) you should use the new solution.
Note: Requires PHP 7+. If you are working with a lower version there is a backporting function on php.net in the comments.
function generateRandom($length, $type, $gen){
switch ($type){
case 'A':
$data = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ";
break;
case 'N':
$data = '0123456789';
break;
case 'M':
$data = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789";
break;
default:
$data = "";
break;
}
static $randoms = array();
$rd = "";
$max = strlen($data) - 1;
for($i = 0; $i < $length; $i++){
$rd_key = $length.$type.$gen.$i;
if(!isset($randoms[$rd_key])){
$randoms[$rd_key] = random_int(0, $max);
}
$rd .= $data[$randoms[$rd_key]];
}
if ( $gen == 'U') $rd = strtoupper($rd);
if ( $gen == 'L') $rd = strtolower($rd);
return $rd;
}
Example Result
Generated with code:
print("<table>".
"<tr>".
"<th>Function</th>".
"<th>Secure result</th>".
"<th>Secure is correct</th>".
"<th>Normal result</th>".
"<th>Normal is correct</th>".
"</tr>");
$cache_normal = array();
$cache_secure = array();
// 12 possibilities, there has to be one double element
for($i = 0; $i < 13; $i++){
$length = rand(3, 5);
$type = rand(0, 2);
switch($type){
case 1: $type = "N"; break;
case 2: $type = "M"; break;
case 0:
default: $type = "A"; break;
}
$gen = rand(0, 1);
switch($gen){
case 1: $gen = "U"; break;
case 0:
default: $gen = "L"; break;
}
$secure = generateRandomSecure($length, $type, $gen);
if(!isset($cache_secure[$length.$type.$gen])){
$cache_secure[$length.$type.$gen] = $secure;
$secure_corr = "-";
}
elseif($cache_secure[$length.$type.$gen] == $secure){
$secure_corr = "<i>found and correct</i>";
}
else{
$secure_corr = "<i>found but wrong</i>";
}
$normal = generateRandom($length, $type, $gen);
if(!isset($cache_normal[$length.$type.$gen])){
$cache_normal[$length.$type.$gen] = $normal;
$normal_corr = "-";
}
elseif($cache_normal[$length.$type.$gen] == $normal){
$normal_corr = "<i>found and correct</i>";
}
else{
$normal_corr = "<i>found but wrong</i>";
}
print("<tr>".
"<td><code>generateRandom(".$length.", ".$type.", ". $gen.")</code></td>".
"<td>'".$secure."'</td>".
"<td>".$secure_corr."</td>".
"<td>'".$normal."'</td>".
"<td>".$normal_corr."</td>".
"</tr>"
);
}
print("</table>");
Original answer: I think I would store the seed of the random. You can use a static (or global) variable which contains the parameters as the keys and the seed as the value.
function generateRandom($length, $type, $gen){
static $seeds = array();
if(!isset($seeds[$length.$type.$gen])){
$seeds[$length.$type.$gen] = microtime(true) * 1000000;
}
srand($seeds[$length.$type.$gen]);
$rd = "";
switch ($type) {
case 'A':
$data = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ";
break;
case 'N':
$data = '0123456789';
break;
case 'M':
$data = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789";
break;
default:
$data = "";
break;
}
$len = strlen($data);
for($i = 0; $i < $length; $i++){
$rd .= $data[rand() % $len];
}
if ( $gen == 'U') $rd = strtoupper($rd);
if ( $gen == 'L') $rd = strtolower($rd);
return $rd;
}
This code results in the following. I hope this is what you are trying to do:
var_dump(generateRandom(3, "A", "L")); // prints e.g. string(3) "wkr"
var_dump(generateRandom(4, "A", "L")); // prints e.g. string(3) "rppd"
var_dump(generateRandom(4, "N", "L")); // prints string(4) "9377"
var_dump(generateRandom(3, "A", "L")); // prints string(3) "wkr" again
After a reload all the values are different again (because the seeds change).