2

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);
5
  • 2
    It won't be very random if it is the same. I think you're very confused.😏 Either something is random, or not. It's not that difficult. If you're looking for something that looks random but isn't really, you could use hashes. Most hashes stay the same when the input stays the same. Another way to use the same real random number sereral times is to store it (cookie, sesssion, database). Commented May 5, 2019 at 8:11
  • Hashes is a good idea, but I'm generating not only this once, with the same parameters, I need thousand of result in the same time, so if very result it must be different. So it a random that's fixed only in one result. Commented May 5, 2019 at 8:20
  • Guaranteeing that some random number is actually really unique is quite difficult. Even the build-in function uniqid() warns you about this, and its whole purpose is to generate an unique id. Commented May 5, 2019 at 8:28
  • I feel kind of ignored. Doesn't my answer work? Is it not what you are trying? Can you give any feedback please? Commented May 5, 2019 at 8:30
  • @user11209806 ok :) I was just a bit irritated because you were answering to everyone except me :) Commented May 5, 2019 at 8:37

1 Answer 1

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

enter image description here

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

Sign up to request clarification or add additional context in comments.

14 Comments

I was afraid of this. Seeding the random number generator is a good idea, but it severely reduces the 'randomness' of generateRandom(). Not your fault by the way. This basically turns this function into a hash function with unknown properties, due to the usage of an undocumented random generator.
@KIKOSoftware I totally agree with you. This is not a real random value anymore. Nevertheless I also use the word "random" instead of "pseudo random". For security things like passwords ect. this is not acceptable. But for things like creating random exampels for tests this is good enough I think. It depends on the puropse I think. But this is not random anymore. You are right.
Well, I guess we agree. My problem is that there's no way of characterizing the output. user11209806 want unqiue values, but this cannot garantee that in any way. A hashing algorithm has know properties. Example: MD5: "Non-discoverability: Every pair of nonidentical files will translate into a completely different hash value, even if the two files differ only by a single bit. Using today's technology, it is not possible to discover a pair of files that translate to the same hash value.", and it's MD5!
@KIKOSoftware hmm, I see your point. I didn't even think about that. The thing about hashes is that you will have the exact same result every time. I think this is wrong for this question. But the only argument for my solution is the same as before: For someting like tests it's good enough. Maybe you could compare hashing with the rand() function? Then you could also exchange the rand() function with something better (random_int() is cryptographically secure)
@miile7 The code is running in Php 7.++ environment, I tested it's 100% good. But The app where I'm doing modifications is php 5.. so this is why random_int isn't working right ?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.