Advanced Algoithm issues to generate unique 6 char long code - php

I have used this algorithm to generate 100 codes. Now Once again i have searched the threads on this site and on google before posting. The algorthms found do work in generating the code the issue I got is i have to generate UNIQUE codes from the one i already have. The problem i am finding is all the scripts are all failing to execute.
So basically I have an ARRAY holding 100 voucher codes I need to generate 400 more voucher codes however while my algorithm's works it keeps timing out due to it taking to long to execute. I have tried several other algorithms from the threads on Stack overflow but for some reason they all keep timing out. I need advice on what I can do to my algorithm to actually produce 400 more unique 6 Char codes.
Here is script I have
/**
**Use this portion to get my current 100 codes in an array which i use
**/
$redeem = 'THIS IS A STRING WHICH CREATES AN ARRAY CONTIANING 100 VALUES';
$redeem = preg_replace('/\s+/', '', $redeem);
$redeem_code = str_split($redeem, 6);
/**
**Function generates unique 6 letter voucher codes
**
**/
function random_str($length, $keyspace = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ')
{
$str = '';
$max = mb_strlen($keyspace, '8bit') - 1;
for ($i = 0; $i < $length; ++$i) {
$str .= $keyspace[mt_rand(0, $max)];
}
return $str;
}
/**
**This is the query which checks against my array and then echo's a valid code
**
**/
$redeem_count = count($redeem_code);
$i = 0;
$ia = 1;
while($i <= 500){
$string = random_str(6);
if(in_array($string, $redeem_code))
{
echo $string;
$i= $i+1;
}
}
Constant Error Message on All functions tried.
Fatal error: Maximum execution time of 120 seconds exceeded in C:\wamp\www\nfr_chip.php on line 115

You never add anything to the array and only increase $i if the code already exist.
This should work...
$redeem_count = count($redeem_code);
while($redeem_count <= 500) {
$string = random_str(6);
if(!in_array($string, $redeem_code))
{
$redeem_code[] = $string;
$redeem_count++;
}
}
And for the way you are splitting your string with codes, instead of using preg_replace (avoid regex unless you really need it):
$redeem_code = explode(" ", $redeem);

You can safely use openssl_random_pseudo_bytes with bin2hex to generate pseudo-random, as the name implies, strings.
Here's an example:
for ($i=1;$i<=5;$i++){
print bin2hex(openssl_random_pseudo_bytes(3)) . PHP_EOL;
}
//output
9282fb
3b9798
c187a0
a058e3
df2e4b
3 bytes will give you a 6 char string

Related

random_int generating values less than minimum

I am generating passwords with random_int, but I noticed something weird. Sometimes (purely random), it generates a password less than the minimum value. For example, I set 10 and 15 the limits and once every circa 50-70 tries it pops out a 2-3 character long password. Is there something wrong with my script? It's hard to reproduce the output, just refresh the script till you get a similar result.
<?php
$r_number = random_int( 10 , 15 );
function random_str(
$length,
$keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,./<>?;:"|[]{}-=_+`~!##$%^&*'
) {
$str = '';
$max = mb_strlen($keyspace, '8bit') - 1;
if ($max < 1) {
throw new Exception('$keyspace must be at least two characters long');
}
for ($i = 0; $i < $length; ++$i) {
$str .= $keyspace[random_int(0, $max)];
}
return $str;
}
$password = random_str($r_number);
echo $password;
?>
Going on a limb here, but...
If the generated password happens to include < - which is in your default $keyspace - and you are viewing the results in a browser, then the < is treated as the start of an HTML tag and won't be displayed, nor will anything after it unless a > happens to be chosen.
That's the only thing I can think of that would be causing this. Try echo htmlspecialchars($password); to output it.

PHP: Generate random Code excluding (0, 1, O and L)

I am trying to generate random voucher code applying the following rules:
Alphanumeric combination 5 characters in capital case (A-Z, 0-9, and take away 1, 0, I, O).
This is my try
<?php
function generateRandomString($length = 5) {
return substr(str_shuffle("23456789ABCDEFGHIJKMNPQRSTUVWXYZ"), 0, $length);
}
echo generateRandomString();
?>
but i am not sure if there is a better way of doing this
If you need to call this function lots of times, your current implementation will be very slow, because it uses much more calls of random function than it is necessary (if $length < 32). Also if your set of allowed characters is smaller than number of characters in the result, your current implementation will return wrong result too. And also your implementation does not allow repeating of characters in the result, but in the specification it is not forbidden to repeat characters.
A little more accurate solution is to use array_rand():
function generateRandomString($length = 5) {
$allowed = str_split('23456789ABCDEFGHIJKMNPQRSTUVWXYZ'); // it is enough to do it once
$res = '';
foreach (array_rand($allowed, $length) as $k)
$res .= $allowed[$k];
return $res;
}
function generateRandom($length = 5) {
$possibleChars = '123456789ABCDEFGHJKMNPQRSTUVWXYZ';
$rndString = '';
for ($i = 0; $i < $length; $i++) {
$rndString .= $possibleChars[rand(0, strlen($possibleChars) - 1)];
}
return $rndString;
}
echo generateRandom();
Here you can define the characters which you want to have in your random string.
The problem with your function is that any char will be just used 1 time per call. Its not really random. And the lenght of the random string would also be limited to the amount of characters you have.
For example: AAAAA is not possible with your function, with mine it is.
If you need a string longer than your charset, that method will fail. Please can you try the code below;
<?php
function generateRandomString($length = 5) {
$chars = "23456789ABCDEFGHIJKMNPQRSTUVWXYZ"; //Your char-set
$charArray = str_split($chars); //Your array representation of chars
$charCount = strlen($chars); //Your char-set length
$result = "";
//Loop throught required `$length`
for($i=1;$i<=$length;$i++)
{
$randChar = rand(0,$charCount-1); //Pick a random char in range of our chars
$result .= $charArray[$randChar]; //Concatenate picked char to result
}
return $result;
}
echo generateRandomString(75);
?>
Here is a working example: https://ideone.com/D1EQ9T
Hope this helps.

Random generator returning endless duplicates

I am trying to create a random string which will be used as a short reference number. I have spent the last couple of days trying to get this to work but it seems to get to around 32766 records and then it continues with endless duplicates. I need at minimum 200,000 variations.
The code below is a very simple mockup to explain what happens. The code should be syntaxed according to 1a-x1y2z (example) which should give a lot more results than 32k
I have a feeling it may be related to memory but not sure. Any ideas?
<?php
function createReference() {
$num = rand(1, 9);
$alpha = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz"), 0, 1);
$char = '0123456789abcdefghijklmnopqrstuvwxyz';
$charLength = strlen($char);
$rand = '';
for ($i = 0; $i < 6; $i++) {
$rand .= $char[rand(0, $charLength - 1)];
}
return $num . $alpha . "-" . $rand;
}
$codes = [];
for ($i = 1; $i <= 200000; $i++) {
$code = createReference();
while (in_array($code, $codes) == true) {
echo 'Duplicate: ' . $code . '<br />';
$code = createReference();
}
$codes[] = $code;
echo $i . ": " . $code . "<br />";
}
exit;
?>
UPDATE
So I am beginning to wonder if this is not something with our WAMP setup (Bitnami) as our local machine gets to exactly 1024 records before it starts duplicating. By removing 1 character from the string above (instead of 6 in the for loop I make it 5) it gets to exactly 32768 records.
I uploaded the script to our centos server and had no duplicates.
What in our enviroment could cause such a behaviour?
The code looks overly complex to me. Let's assume for the moment you really want to create n unique strings each based on a single random value (rand/mt_rand/something between INT_MIN,INT_MAX).
You can start by decoupling the generation of the random values from the encoding (there seems to be nothing in the code that makes a string dependant on any previous state - excpt for the uniqueness). Comparing integers is quite a bit faster than comparing arbitrary strings.
mt_rand() returns anything between INT_MIN and INT_MAX, using 32bit integers (could be 64bit as well, depends on how php has been compiled) that gives ~232 elements. You want to pick 200k, let's make it 400k, that's ~ a 1/10000 of the value range. It's therefore reasonable to assume everything goes well with the uniqueness...and then check at a later time. and add more values if a collision occured. Again much faster than checking in_array in each iteration of the loop.
Once you have enough values, you can encode/convert them to a format you wish. I don't know whether the <digit><character>-<something> format is mandatory but assume it is not -> base_convert()
<?php
function unqiueRandomValues($n) {
$values = array();
while( count($values) < $n ) {
for($i=count($values);$i<$n; $i++) {
$values[] = mt_rand();
}
$values = array_unique($values);
}
return $values;
}
function createReferences($n) {
return array_map(
function($e) {
return base_convert($e, 10, 36);
},
unqiueRandomValues($n)
);
}
$start = microtime(true);
$references = createReferences(400000);
$end = microtime(true);
echo count($references), ' ', count(array_unique($references)), ' ', $end-$start, ' ', $references[0];
prints e.g. 400000 400000 3.3981630802155 f3plox on my i7-4770. (The $end-$start part is constantly between 3.2 and 3.4)
Using base_convert() there can be strings like li10, which can be quite annoying to decipher if you have to manually type the string.

PHP Runtime Issue when Breaking a 10,000 char string into segments

$chapter is a string that stores a chapter of a book with 10,000 - 15,000 characters. I want to break up the string into segments with a minimum of 1000 characters but officially break after the next whitespace, so that I don't break up a word. The provided code will run successfully about 9 times and then it will run into a run time issue.
"Fatal error: Maximum execution time of 30 seconds exceeded in D:\htdocs\test.php on line 16"
<?php
$chapter = ("10000 characters")
$len = strlen($chapter);
$i=0;
do{$key="a";
for($k=1000;($key != " ") && ($i <= $len); $k = $k+1) {
$j=$i+$k; echo $j;
$key = substr($chapter,$j,1);
}
$segment = substr ($chapter,$i,$k);
$i=$j;
echo ($segment);
} while($i <= $len);
?>
I think your method of writing it has too much overhead, while increasing max_execution_time will help, not everyone is able to modify their server settings. This simple thing split 15000 bytes of lorum ipsum text (2k Words) into 1000 character segments. I assume it would do well with more, as the execution time was fairly quick.
//Define variables, Set $x as int(1 = true) to start
$chapter = ("15000 bytes of Lorum Ipsum Here");
$sections = array();
$x = 1;
//Start Splitting
while( $x ) {
//Get current length of $chapter
$len = strlen($chapter);
//If $chapter is longer than 1000 characters
if( $len > 1000 ) {
//Get Position of last space character before 1000
$x = strrpos( substr( $chapter, 0, 1000), " ");
//If $x is not FALSE - Found last space
if( $x ) {
//Add to $sections array, assign remainder to $chapter again
$sections[] = substr( $chapter, 0, $x );
$chapter = substr( $chapter, $x );
//If $x is FALSE - No space in string
} else {
//Add last segment to $sections for debugging
//Last segment will not have a space. Break loop.
$sections[] = $chapter;
break;
}
//If remaining $chapter is not longer than 1000, simply add to array and break.
} else {
$sections[] = $chapter;
break;
}
}
print_r($sections);
Edit:
Tested with 5k Words (33K bytes) In a fraction of a second. Divided the text up into 33 segments. (Whoops, I had it set to divide into 10K character segments, before.)
Added verbose comments to code, as to explain what everything does.
Here is a simple function to do that
$chapter = "Your full chapter";
breakChapter($chapter,1000);
function breakChapter($chapter,$size){
do{
if(strlen($chapter)<$size){
$segment=$chapter;
$chapter='';
}else{
$pos=strpos($chapter,' ', $size);
if ($pos==false){
$segment=$chapter;
$chapter='';
}else{
$segment=substr($chapter,0,$pos);
$chapter=substr($chapter,$pos+1);
}
}
echo $segment. "\n";
}while ($chapter!='');
}
checking each character is not a good option and is resource/time intensive
PS: I have not tested this (just typed in here), and this may not be the best way to do this. but the logic works!
You are always reading the $chapter from the start. You should delete the already read characters from $chapter so you will never read much more than 10000 characters. If you do this, you must also tweak the cycles.
try
set_time_limit(240);
at the begining of the code. (this is the ThrowSomeHardwareAtIt aproach )
It can be done in just one single line, wich speeds up your code a lot.
echo $segment = substr($chapter, 0, strpos($chapter, " ", 1000));
It wil take the substring of the chapter until 1000 + some characters until the first space.

PHP code for generating decent-looking coupon codes (mix of letters and numbers)

For an ecommerce site I want to generate a random coupon code that looks better than a randomly generated value. It should be a readable coupon code, all in uppercase with no special characters, only letters (A-Z) and numbers (0-9).
Since people might be reading this out / printing it elsewhere, we need to make this a simple-to-communicate value as well, perhaps 8-10 characters long.
Something like perhaps,
AHS3DJ6BW
B83JS1HSK
(I typed that, so it's not really that random)
$chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$res = "";
for ($i = 0; $i < 10; $i++) {
$res .= $chars[mt_rand(0, strlen($chars)-1)];
}
You can optimize this by preallocating the $res string and caching the result of strlen($chars)-1. This is left as an exercise to the reader, since probably you won't be generating thousands of coupons per second.
Try this:
substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, 10)
Why don't keep it simple?
<?php
echo strtoupper(uniqid());
?>
Always returns 13 character long uppercased random code.
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. Simple PHP coupon code generator
Example:
coupon::generate(8); // J5BST6NQ
http://webarto.com/35/php-random-string-generator
Here you go.
function randr($j = 8){
$string = "";
for($i=0;$i < $j;$i++){
srand((double)microtime()*1234567);
$x = mt_rand(0,2);
switch($x){
case 0:$string.= chr(mt_rand(97,122));break;
case 1:$string.= chr(mt_rand(65,90));break;
case 2:$string.= chr(mt_rand(48,57));break;
}
}
return strtoupper($string); //to uppercase
}
If there are no security requirements for these, then you don't really need randomly generated codes. I would just use incremental IDs, such as those generated by whatever RDBMS you use. Optionally, if you have different types of coupons, you could prefix the codes with something, e.g.:
CX00019 QZ0001C
CX0001A QZ0001D
CX0001B QZ0001E
Alternately, you could even use dictionary words in the coupon, as such coupon codes are easier to remember and faster for users to type. Companies like Dreamhost use these for their promo codes, e.g.:
Promo60
NoSetupFee
YELLOWGORILLA82
Some of these are obviously human-created (which you might want to have the option of), but they can also be generated using a dictionary list. But even if they are randomly-generated nonsense phrases, the fact that the characters follow a logical pattern still makes it much more user-friendly than something like R7QZ8A92F1. So I would strongly advise against using the latter type of coupon codes just on the basis that they "look cool". Your customers will thank you.
$size = 12;
$string = strtoupper(substr(md5(time().rand(10000,99999)), 0, $size));
function generateCouponCode($length = 8) {
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$ret = '';
for($i = 0; $i < $length; ++$i) {
$random = str_shuffle($chars);
$ret .= $random[0];
}
return $ret;
}
you can find a lot of function in php rand manual
http://php.net/manual/en/function.rand.php
i like this one
<?php
//To Pull 8 Unique Random Values Out Of AlphaNumeric
//removed number 0, capital o, number 1 and small L
//Total: keys = 32, elements = 33
$characters = array(
"A","B","C","D","E","F","G","H","J","K","L","M",
"N","P","Q","R","S","T","U","V","W","X","Y","Z",
"1","2","3","4","5","6","7","8","9");
//make an "empty container" or array for our keys
$keys = array();
//first count of $keys is empty so "1", remaining count is 1-7 = total 8 times
while(count($keys) < 8) {
//"0" because we use this to FIND ARRAY KEYS which has a 0 value
//"-1" because were only concerned of number of keys which is 32 not 33
//count($characters) = 33
$x = mt_rand(0, count($characters)-1);
if(!in_array($x, $keys)) {
$keys[] = $x;
}
}
foreach($keys as $key){
$random_chars .= $characters[$key];
}
echo $random_chars;
?>
$length = 9;
$code = (strtoupper(substr(md5(time()), 0, $length)));
Just Write
$voucher_no = date('ymd') . rand(1000, 9999);
while(SapItem::where('voucher_no', $voucher_no)->exists()){
$voucher_no = date('ymd') . rand(1000, 9999);
}
Output: 2204171447

Categories