Random repeats similar strings, even after changing seed - php

How can I get this random string generator to create random strings. I keep getting repeats. The arrays generally consist of between 0 - 10 things, but still it is getting the same number of beds and baths on the repeats, I know that statistically it is messed up.
How can I elminate repeats?
for ($i = 0; $i <= 1000000; $i++) {
srand($i);
$price = rand(20000, 1000000);
$bed = rand(0, 20);
$bath = rand(0, 7);
$addressnum = rand(100, 10000);
$address = (int) preg_replace('/\D/', '', $addressnum) . " lol st";
$province = $f_contents[rand(0, count($f_contents) - 1)];
$postedby = 3;
$description = $de_contents[rand(0,count($de_contents) - 1)];
$status = "Unsold";
$type = $status_a[array_rand($status_a)];
$category = $category_type[array_rand($category_type)];
$size = rand(100,100000);
$builtin = rand(1850, 2013);
$queryString = "INSERT INTO listings
(PRICE, ADDRESS, PROVINCE, DESCRIPTION, STATUS, TYPE, CATEGORY, SIZE, BUILTIN, BED, BATH, POSTED_BY) VALUES
($price, '$address', '$province', '$description', '$status', '$type', '$category', $size, $builtin, $bed, $bath, $postedby)";
echo $queryString . "<br>";
$query = $db -> query($queryString);
}

Stop using rand(). Using mt_rand() instead should solve this problem.
I've come across problems several times with rand() and repeated values. I have to admit that in those cases I never really took the time to check why rand() seems so wonky.

Take srand() outside the loop. srand() should be called ONCE, and only once, in your program. Thereafter, rand() will produce random results. If you call srand() repeatedly, you're not getting random numbers at all, you're getting a hash value of the seeds you call it with.
Sure, switching to mt_rand() will give you even higher-quality random numbers, but that wasn't the problem with your code.

Related

PHP replace dash with 0 from array when inserting to mySQL

I'm inserting/updating a mysql table from json URL, but some of the values in $points contain a dash and I want to amend to a zero (or null would be fine) when updating so that I can have the column set to INT.
I know how to simply replace all - to 0 in mysql but stuck when it comes to trying to do as part of update from a json URL. My code is:
for ($i = 0; $i < $length; $i++) {
$sus = $array['formguide'][$i]['SUSPENSION'];
$wpoints = $array['formguide'][$i]['WEEKPOINTS'];
$tcode = $array['formguide'][$i]['TEAMCODE'];
$val = $array['formguide'][$i]['VALUE'];
$points = $array['formguide'][$i]['POINTS'];
$pname = $array['formguide'][$i]['PLAYERNAME'];
$tname = $array['formguide'][$i]['TEAMNAME'];
$sixwpoints = $array['formguide'][$i]['SIXWEEKPOINTS'];
$injury = $array['formguide'][$i]['INJURY'];
$playerid = $array['formguide'][$i]['PLAYERID'];
$pos = $array['formguide'][$i]['POS'];
//insert or update values into mysql
$sql = "INSERT INTO formguide (suspension, weekpoints, teamcode,
value, points, playername, teamname,
sixweekpoints, injury, playerid, pos)
VALUES ('$sus', '$wpoints', '$tcode','$val','$points','$pname','$tname',
'$sixwpoints','$injury','$playerid','$pos')
ON DUPLICATE KEY UPDATE suspension='$sus', weekpoints='$wpoints',
teamcode='$tcode', value='$val', points='$points', playername='$pname',
teamname='$tname', sixweekpoints='$sixwpoints', injury='$injury',
playerid='$playerid', pos='$pos'";
I tried REPLACE() on points within the UPDATE() section i.e.:
...points=REPLACE('$points','-','0'), playername='$pname', ...
however that didn't work.
Any ideas how I can do this, or is there an alternative to have the points column as INT and accept a dash?
Thanks
REPLACE is for modifying values coming from SQL, whereas you want to modify a value coming from PHP.
Use str_replace instead.
$points = str_replace('-', '0', $points);
First, you need to escape or cast all values to avoid SQL injection vulnerabilities. Since you did not post your table schema, I'm guessing the types. mysqli_real_escape_string() is for strings, (int) and (float) for numbers of the respective type.
Doing that, your original problem is solved automatically, as PHP returns 0, if you cast '-' to integer.
Second, your query is a usecase for a proper use of REPLACE, which works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
for ($i = 0; $i < $length; $i++)
{
$sus = mysqli_real_escape_string($link, $array['formguide'][$i]['SUSPENSION']);
$wpoints = (int) $array['formguide'][$i]['WEEKPOINTS'];
$tcode = mysqli_real_escape_string($link, $array['formguide'][$i]['TEAMCODE']);
$val = (float) $array['formguide'][$i]['VALUE'];
$points = (int) $array['formguide'][$i]['POINTS'];
$pname = mysqli_real_escape_string($link, $array['formguide'][$i]['PLAYERNAME']);
$tname = mysqli_real_escape_string($link, $array['formguide'][$i]['TEAMNAME']);
$sixwpoints = (int) $array['formguide'][$i]['SIXWEEKPOINTS'];
$injury = mysqli_real_escape_string($link, $array['formguide'][$i]['INJURY']);
$playerid = (int) $array['formguide'][$i]['PLAYERID'];
$pos = (int) $array['formguide'][$i]['POS'];
// Insert or update values into mysql
$sql = "REPLACE INTO formguide SET
suspension='$sus',
weekpoints=$wpoints,
teamcode='$tcode',
value=$val,
points=$points,
playername='$pname',
teamname='$tname',
sixweekpoints=$sixwpoints,
injury='$injury',
playerid=$playerid,
pos=$pos
";
// ...
}

PHP mysqli insert only works once

I've got a script that I needed to change since the data which is going to be inserted into the db got too big to do it at once. So I created a loop, that splits up the array in blocks of 6000 rows and then inserts it.
I don't know exactly if the data is to big for the server to process at once or if it's too big to upload, but atm I got both steps split up in these 6000s blocks.
Code:
for ($j = 0; $j <= ceil($alength / 6000); $j++){
$array = array_slice($arraysource, $j * 6000, 5999);
$sql = "INSERT INTO Ranking (rank, name, score, kd, wins, kills, deaths, shots, time, spree) VALUES ";
foreach($array as $a=>$value){
//transforming code for array
$ra = $array[$a][0];
$na = str_replace(",", ",", $array[$a][1]);
$na = str_replace("\", "\\\\", $na);
$na = str_replace("'", "\'", $na);
$sc = $array[$a][2];
$kd = $array[$a][3];
$wi = $array[$a][4];
$ki = $array[$a][5];
$de = $array[$a][6];
$sh = $array[$a][7];
$ti = $array[$a][8];
$sp = $array[$a][9];
$sql .= "('$ra',' $na ','$sc','$kd','$wi','$ki','$de','$sh','$ti','$sp'),";
}
$sql = substr($sql, 0, -1);
$conn->query($sql);
}
$conn->close();
Right now it only inserts the first 5999 rows, but not more as if it only executed the loop once. No error messages..
Don't know if this'll necessarily help, but what about using array_chunk, array_walk, and checking error codes (if any)? Something like this:
function create_query(&$value, $key) {
//returns query statements; destructive though.
$value[1] = str_replace(",", ",", $value[1]);
$value[1] = str_replace("\", "\\\\", $value[1]);
$value[1] = str_replace("'", "\'", $value[1]);
$queryvalues = implode("','",$value);
$value = "INSERT INTO Ranking (rank, name, score, kd, wins, kills, deaths, shots, time, spree) VALUES ('".$queryvalues."');";
}
$array = array_chunk($arraysource, 6000);
foreach($array as $key=>$value){
array_walk($value,'create_query');
if (!$conn->query($value)) {
printf("Errorcode: %d\n", $conn->errno);
}
}
$conn->close();
Secondly, have you considered using mysqli::multi_query? It'll do more queries at once, but you'll have to check the max allowed packet size (max_allowed_packet).
Another tip would be to check out the response from the query, which your code doesn't include.
Thanks for the tips but I figured it out. Didn't think about this ^^
it was the first line after the for loop that i didnt include in my question:
array_unshift($array[$a], $a + 1);
this adds an additional value infront of each user, the "rank". But the numbers would repeat after one loop finishes and it can't import users with the same rank.
now it works:
array_unshift($array[$a], $a + 1 + $j * 5999);

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 distribute percentage based on total numbers

I'm trying to distribute 100% to total numbers (not equally), it can be done manually but I'm looking for a automatically way in PHP. I had to open calculator and get it done for manual.
What I'm trying to achieve is the result similar to this:
$value = 10000;
$total_numbers = 9
$a1 = $value*0.2;
$a2 = $value*0.175;
$a3 = $value*0.15;
$a4 = $value*0.125;
$a5 = $value*0.1;
$a6 = $value*0.08;
$a7 = $value*0.07;
$a8 = $value*0.05;
$a9 = $value*0.04;
So as you can see, the first variables have more quantity than the later ones, but if you add these, it will be 1 which is 100%. So lets say I have total_numbers=20 then I'll have to re-write it and get a calculator and do it the hard way to accomplish my goal. Is there any way this can be done automatically with a function where I can just tell the total number and it can distribute it to proportions or something?
The first one will always be bigger than rest, then second one bigger than rest but smaller than first, third one being greater than rest but small than first and second, and so on.
function distributeValue($value, $num) {
$parts = $num * ($num + 1) / 2;
$values = [];
for ($i = $num; $i > 1; --$i) {
$values[] = round($value * $i / $parts);
}
$values[] = $value - array_sum($values);
return $values;
}
var_dump(distributeValue(10000, 9));
This works by calculating the $numth triangle number (the number you get by adding all the numbers from 1 to $num) and dividing the total value up into this number of parts.
It then starts by taking $num parts, then $num-1 parts and so on.
Since it's rounding the numbers, the last step is to take the total minus all the other values which is around one part. If you are fine with getting floats instead of ints out, then you can remove the $values[] = $value - array_sum($values); line and change the condition of the for loop to $i > 0.

different value of variable while inserting

I want to generate a pair of random numbers 1234567890-9876543210 (10 digits each)
I made this code. It works fine it generates a pair of random numbers BUT if I try to insert it into database I get same results multiple times. Let's say I get 1234567890 more than once. If I echo the insert statement I get different results but when I want to query it into database I get same results.
$numbers = array(0,1,2,3,4,5,6,7,8,9);
srand(time());
$f = fopen('sql0.txt', 'w');
for($i=0;$i<100000;$i++)
{
$r = NULL;
$r2 = NULL;
for($x=0;$x<10;$x++)
{
$n = rand(0,9);
$r .= $numbers[$n];
}
for($x=0;$x<10;$x++)
{
$n1 = rand(0,9);
$r2 .= $numbers[$n1];
}
echo("INSERT INTO ci_codes VALUES (NULL, '$r', '$r2', '0')<br>");
}
Do you need the INSERT expression inside your loop? That might cause the trouble.
As others have mentioned, it is better to just generate the numbers once with the php function, then run your MySql Query.
$r = mt_rand(0, 10000000);
$r2 = mt_rand(0, 10000000);
echo("INSERT INTO ci_codes VALUES (NULL, '$r', '$r2', '0'");

Categories