Stopping a PHP loop when updating MySQL database - php

I'm creating a basic main menu for a stock market simulator where the price of a company will be updated periodically. For testing purposes, I need to make a loop to display the price of a share on the website five times (with the website automatically updating without refreshing) and to update the database at the same time.
I have successfully wrote some code which will both update the database with the current share price and will also update the website as well. However, when I have tried to include a loop I have come to a problem. I have included a loop to iterate five times but the problem that I am having is that the code continues to iterate even after five tries.
PHP:
<?php
$conn = mysqli_connect("localhost", "root", "", "prices");
if ($conn->connect_error)
{
die("Connection error: ". $conn->connect_error);
}
$result = $conn->query("SELECT `price` FROM `priceTable` WHERE `company` = 'Bawden'");
$x = 0;
if ($result->num_rows > 0)
{
while ($row = $result->fetch_assoc())
{
echo $row['price'];
echo '<br><br>';
echo $x;
if ($x < 5)
{
$random = (rand(3300, 3700) / 100);
$sql = $conn->query("UPDATE `priceTABLE` SET `price` = '$random' WHERE `company` = 'Bawden'");
$x++;
}
}
}
?>
The above code will be displayed in a separate document with Javascript code and I can post this if required in the original post however I originally chose not to as I believe this is a PHP only problem. I have chosen to display $x to see if the value will increment. However, when running, the value of $x will stay at 0.
My expected result is that, on the website, there will only be five different updates and in the database, the database will only be updated five times.
However, my actual result is that the website and database are both continuously being updated, not stopping after five times.

I'm trying to limit the update command to only 5 updates yes. At the
moment, for testing purposes, there is only one company in my database
with one price only. So I'm updating this one company's price five
times
If you need to do the update 5 times for each row returned from the database, change your if statement to a for loop. Change this :-
if ($x < 5)
{
$random = (rand(3300, 3700) / 100);
$sql = $conn->query("UPDATE `priceTABLE` SET `price` = '$random' WHERE `company` = 'Bawden'");
$x++;
}
to this
for ($x = 0, $x < 5, $x++)
{
$random = (rand(3300, 3700) / 100);
$sql = $conn->query("UPDATE `priceTABLE` SET `price` = '$random' WHERE `company` = 'Bawden'");
}
This will repeat the process exactly 5 times and not rely on a separate counter (remove the other references to $x). Not sure why you would want to update the same record 5 times with different random values though.

The else will break the first loop, the second one will stop on the first while loop.
while ($row = $result->fetch_assoc())
{
echo $row['price'];
echo '<br><br>';
echo $x;
if ($x < 5)
{
$random = (rand(3300, 3700) / 100);
$sql = $conn->query("UPDATE `priceTABLE` SET `price` = '$random' WHERE `company` = 'Bawden'");
$x++;
}else{
break;
}
break;
}

What makes you think the loop should stop after 5 iterations?
You need to add the condition $x<5 in the while ($row = $result->fetch_assoc())
Edit following your comment
What you initially wrote is something like loop hundreds of times if need be and do something in the first 5 occurrences (starting loop 6, keep looping but do nothing).
Now for the 2nd half of your comment, I'm not sure what you mean.
What I see in your code is:
Select all prices for company = 'Bawden'
Update all the prices for company = 'Bawden' 5 times (loop) with a random value, the same one, on all the records.
Not enough information to tell for sure but I don't think it makes sense: on one hand, you except to have several records under company = 'Bawden (= reason why you created a loop), on the other hand, your update feels like it is written under the assumption there would be 1 record only...
Are you missing something like a price date from your table? What is the primary key of priceTable?
Try to post more technical details about your table (definition, sample of data) or it will be complicated to help further.

Related

Recursive call for cron job

I have a three PHP script, from which two are running as a separate cron job each day in server.
First script(get_products.php), make curl call to external server to get all products data and stored that data in database. Note that there are around 10000 products and increasing each day.
In Second script(find_related.php), selects products from database stored by first script, perform some operations and store operational data in another database. Each product have 10 rows so in this database there is around 100000 rows. This script is running as cron. Sometimes the script is not executed fully and that's why, the actual and expecting results are not stored in database. I included this line of code in script: ini_set('max_execution_time', '3600');
But it not works.
Here is the process done in this script:
Normally task is to find 10 related products based on tags. I have around 10300 products stored in my DB. Each time query take one product and their tags and try to randomly find one product tagged with same tag as main product and store the related product data into another DB for third script. Only one product per tag is allowed. If it will not find total of 10 related products then randomly gets products from another DB named bestseller_products.
Here is my code:
$get_all_products = mysql_query('SELECT * FROM store_products');
while($get_products_sql_res = mysql_fetch_array($get_all_products)){
$related_products = array();
$tags = explode(",",$get_products_sql_res['product_tags']);
$product_id = $get_products_sql_res['product_id'];
$product_handle = $get_products_sql_res['product_handle'];
$get_products_sql = mysql_query('SELECT * FROM related_products WHERE product_handle="'.$product_handle.'"');
if (mysql_num_rows($get_products_sql)==0)
{
$count = 0;
foreach($tags as $t){
$get_related_products_sql = mysql_query("SELECT product_handle, product_title, product_image FROM store_products WHERE product_tags like '%".$t."%' AND product_id != '".$product_id."' ORDER BY RAND()");
if(!$get_related_products_sql){
continue;
}
while($get_related_products = mysql_fetch_array($get_related_products_sql) ){
$related_product_title = mysql_real_escape_string($get_related_products['product_title']);
$found = false;
foreach($related_products as $r){
if($r['handle'] == $get_related_products['product_handle']){
$found = true;
break;
}
}
if($found == false){
$related_products[$count]['handle'] = $get_related_products['product_handle'];
mysql_query("INSERT INTO related_products (product_handle, product_id, related_product_title, related_product_image, related_product_handle) VALUES ('$product_handle','$product_id','$related_product_title', '$get_related_products[2]', '$get_related_products[0]')");
$count = $count + 1;
break;
}
}
}
if($count < 10){
$bestseller_products = mysql_query("SELECT product_handle, product_title, product_image FROM bestseller_products WHERE product_id != '".$product_id."' ORDER BY RAND() LIMIT 10");
while($bestseller_products_sql_res = mysql_fetch_array($bestseller_products)){
if($count < 10){
$found = false;
$related_product_title = mysql_real_escape_string($bestseller_products_sql_res['product_title']);
$related_product_handle = $bestseller_products_sql_res['product_handle'];
foreach($related_products as $r){
if($r['handle'] == $related_product_handle){
$found = true;
break;
}
}
if($found == false){
$related_product_image = $bestseller_products_sql_res['product_image'];
mysql_query("INSERT INTO related_products (product_handle, product_id, related_product_title, related_product_image, related_product_handle) VALUES ('$product_handle','$product_id','$related_product_title', '$related_product_image', '$related_product_handle')");
$count = $count + 1;
}
}
}
}
}
}
Third script(create_metafields.php), created metafields in external server using data created by second script. And same problem arises as in second script.
So i want to execute the second script into parts. I mean, not to process all 10000 products in one call but want to run unto parts(1-500,501-1000,1001-1500,..) like it. But dont want to create separate cron jobs. Please suggest if someone has solution. I really need to figure it out.
Thanks in advance!

how to identify unsaved value from database using php mysql

I have to identify unsaved value from mysql table using php and mysql, for example i using table named as numtab and i have already stored some numbers 1, 3, 4, 7, 23, 12, 45 in numb column.
now i have generated one new number randomly(for example 23) and i have to check this number with already stored numbers,
if 23 is exist in the table mean i have to generate another one new number and have to check once again with stored values, this process have to continue till finding unsaved number.
if generated value is not exist in table mean can stop the process and can store this number in table.
here below the format i am currently using
$numb=23;
$qryb="select * from numtab where numb='$numb'";
$results=mysql_query($qryb)or die("ERROR!!");
if(mysql_num_rows($results) == 1)
{
$numb=rand(1,100);
mysql_query("insert query");
}
the problem is above the code is validation once only, its not verifying second time. i think if using for or while loop mean can solve this problem, but i dont know how to do looping, so help me to solve this problem.
You can use in clause like this :
$qryb="select * from numtab where numb in('$numb')";
$results=mysql_query($qryb)or die("ERROR!!");
$count = mysql_num_rows($results);
if ($count > 0) {
echo "number exist in db";
} else {
echo "number does not exist in db";
}
You could make a while() loop to check if the numbers exist in your database. You could also retrieve all numbers from the database, store them in an array and check if the generated number exists within that array.
The first option would be something like this:
do {
$numb=rand(1,100);
$qryb="select * from numtab where numb='$numb'";
$results = mysql_query($qryb) or die("ERROR!!");
} while(mysql_num_rows($results) >= 1)
mysql_query("insert query");
The second option would be something like this:
$query = mysql_query("SELECT DISTINCT(numb) as numb FROM numtab");
// set array
$array = array();
// look through query
while($row = mysql_fetch_assoc($query)){
// add each row returned into an array
$array[] = $row['numb'];
}
do
{
$numb = rand(1,100);
}
while(!in_array ( $numb , $array) ;
mysql_query("insert query");

php unique random number that is not in mysql table- check and then generate

I have this script:
$rrezervim_id = rand(1, 5);
$result = mysql_query("SELECT rrezervim_id FROM pax_list WHERE rrezervim_id='$rrezervim_id'");
if(mysql_num_rows($result) == 1)
{
$rrezervim_id = rand(1, 5);
}
else(mysql_num_rows($result) > 1);
{
echo "$rrezervim_id";
}
What i am trying to do is To generate a Unique Random number using PHP and MySql
i have the value inside table( rrezervim_id)[Values:1,2,3,5] so the only Random number that have to be generated and is free is Number 4.
But with this script something is not working since i am getting even random that are already inserted in the table [Values:1,2,3,5].
Any one can help me, is very important to make a check in mysql before generating the unique number if already exist in table.
First of all, the direct error in your code is
if(mysql_num_rows($result) == 1)
{
$rrezervim_id = rand(1, 5);
}
fails, if you hit a taken number twice. You need a loop, such as
while (mysql_num_rows($result) == 1)
{
$rrezervim_id = rand(1, 5);
$result = mysql_query("SELECT rrezervim_id FROM pax_list WHERE rrezervim_id='$rrezervim_id'");
}
That said, I suspect, that there is more wrong with your code:
If you want to use this "free" random number to insert it into the database at a later point in time, you are wide open to a race condition: Both processes select the same (still free) number, but only on the first insert is it still unique.
This approach can have extremely bad performance, if your field of possible random numbers is nearly full: If you have 80% fill rate, such as in your example, you will on average have 4 "bad" hits, before getting a "good" hit.
I recommend you consider using a database built-in, such as the battle-proven AUTO_INCREMENT as a primary means, then use a formula to create the hard-to-guess pseudo-random from it. A linear feedback shift register can be one approach, while cryptographically combining the auto-generated ID and a (not necessarily unique) pseudo-random stored in the table might be another. Both methods give you linear performance and race-free usage.
you can create unique number in php
<?php
echo uniqid();
?>
But you should use AUTO INCREMENT. If you want to know by which number inserted item is saved use something like this:
function insertUser(){
Global $userName;
$sqlInsert="INSERT INTO person (e_mail)
VALUES ('".$userName."')";
if (!mysql_query($sqlInsert)){
die('Error: ' . mysql_error());
}
$userId = mysql_insert_id();
return $userId;
}
in $userId is last inserted value
Since you are not using AUTO_INCREMENT, a suggestion (which is slow) is to select all the numbers that are valid and pick 1 randomly.
If we have [1,2,3,5,7] and our allowed elements are 1..10, then we have 5 allowed elements(4,6,8,9,10). So we rand(1,5). If we get "1", our next number is 4, if we get "2", our next number is 6. To better explain the idea:
Rand(1,5) Our array Value(available)
1
2
3
1 - 4
5
2 - 6
7
3 8
4 9
5 10
Code example:
$max_num = 100;
$res = mysql_query("SELECT rrezervim_id FROM pax_list ORDER BY rrezervim_id ASC");
$nums = [];
while($row = mysql_fetch_assoc($res)){
$nums[] = $res['rrezervim_id'];
}
$numbers_allowed = $max_num - count($nums); // actual number of allowed elements
$new_num_idx = rand(1, $numbers_allowed); // The selected element's index
(skipping all existing elements)
// in the following loop: $j starts as our lowest options.
// when $new_num_idx reaches 0 - it means that we have skipped
// over $new_num_idx elements. The next available element is
// our choice. $new_num_idx is a countdown
for($i=0,$j=1, $n=count($nums); $i<$n && $new_num_idx > 0; $i++){
while ($nums[$i]>$i+$j){
$j++; $new_num_idx--;
}
}
return $i+$j;

Get a random number betwen 1-200 but leaves out numbers read from query

I need to get a random number between, lets say 1-200, but at the same time I need to prevent selecting a random number that has already been used for a particular REMOTE_ADDR (as stored in a table).
This is what I have so far (I have tried several different approaches):
$ip = $_SERVER['REMOTE_ADDR'];
$query7 = "
SELECT *
FROM IP
WHERE IP = '$ip'
";
$result7 = mysql_query($query7) or die(mysql_error());
$rows7 = mysql_num_rows($result7);
while ($row7 = mysql_fetch_array($result7)){
$id = $row7['ID'];
}
I'm using the random number to pick an image to display, but my users are complaining that the images selected for them is not random enough; ie, the same picture is getting "randomly" selected too often, sometimes showing the same image over and over.
It does not have to be in PHP, if there is another option.
Something like that
// all ids from 1 to 100
$all = array_fill(1, 200, 0);
// remove used
foreach ($used as $i) {
unset($all[$i]);
}
// get survived keys
$keys = array_keys($all);
// get random position, note that the array with keys is 0 based
$j = rand(0, count($all) - 1);
return $keys[$j];
Run your select and instead of using *, only select the id column. Then use:
while($row7[] = mysql_fetch_array($query7));
do{
$rand = rand(0,200);
}while(in_array($rand,$row7));
You can do it all in mysql. Have one table that has your list of images, and another table that has the list of IP addresses and the images that have already been shown to that IP. Then you select and join the tables and order the result randomly.
SELECT image_id FROM images
LEFT JOIN shown_images ON images.image_id=shown_images.image_id AND ip_addr=[#.#.#.#]
WHERE shown_images.image_id IS NULL
ORDER BY RAND() LIMIT 1;
After you show an image to an IP, just insert a record into the shown_images table with the IP and the image ID. That will work right up until that have seen all the images. Then you can delete the records and start over.
This answer assumes that you have 200 items, and collect the items which you do not want to show. Alternatively, you can query only id's of available items and choose from these, you would need to create a table with available items for that.
Create a map which maps consecutive numbers to (non-consecutive) available numbers. Suppose the numbers 1 and 3 are in use, you can map to 2 and 4 (and so on).
Actually, it is possible to use a simple array (not-associative) for this. You can do something like this:
$reserved = array(1, 3); // fill $reserved using your code
$available = array();
for ($i = 1; $i <= 200; $i++) {
if (!in_array($i, $reserved)) {
$available[] = $i;
}
}
if (count($available) > 0) {
$random_index = rand(0, count($available) - 1);
$r = $available[$random_index];
} else {
// Nothing available!
}
There will be nothing to choose when you run out of pictures that have not been displayed yet. In this case, count($available) will be zero. One way to solve this would be to clear your list of displayed images for the current IP and choose again; see also other answers for this.

How can I copy a database table to an array while accounting for skipped IDs?

I previously designed the website I'm working on so that I'd just query the database for the information I needed per-page, but after implementing a feature that required every cell from every table on every page (oh boy), I realized for optimization purposes I should combine it into a single large database query and throw each table into an array, thus cutting down on SQL calls.
The problem comes in where I want this array to include skipped IDs (primary key) in the database. I'll try and avoid having missing rows/IDs of course, but I won't be managing this data and I want the system to be smart enough to account for any problems like this.
My method starts off simple enough:
//Run query
$localityResult = mysql_query("SELECT id,name FROM localities");
$localityMax = mysql_fetch_array(mysql_query("SELECT max(id) FROM localities"));
$localityMax = $localityMax[0];
//Assign table to array
for ($i=1;$i<$localityMax+1;$i++)
{
$row = mysql_fetch_assoc($localityResult);
$localityData["id"][$i] = $row["id"];
$localityData["name"][$i] = $row["name"];
}
//Output
for ($i=1;$i<$localityMax+1;$i++)
{
echo $i.". ";
echo $localityData["id"][$i]." - ";
echo $localityData["name"][$i];
echo "<br />\n";
}
Two notes:
Yes, I should probably move that $localityMax check to a PHP loop.
I'm intentionally skipping the first array key.
The problem here is that any missed key in the database isn't accounted for, so it ends up outputting like this (sample table):
1 - Tok
2 - Juneau
3 - Anchorage
4 - Nashville
7 - Chattanooga
8 - Memphis
-
-
I want to write "Error" or NULL or something when the row isn't found, then continue on without interrupting things. I've found I can check if $i is less than $row[$i] to see if the row was skipped, but I'm not sure how to correct it at that point.
I can provide more information or a sample database dump if needed. I've just been stuck on this problem for hours and hours, nothing I've tried is working. I would really appreciate your assistance, and general feedback if I'm making any terrible mistakes. Thank you!
Edit: I've solved it! First, iterate through the array to set a NULL value or "Error" message. Then, in the assignations, set $i to $row["id"] right after the mysql_fetch_assoc() call. The full code looks like this:
//Run query
$localityResult = mysql_query("SELECT id,name FROM localities");
$localityMax = mysql_fetch_array(mysql_query("SELECT max(id) FROM localities"));
$localityMax = $localityMax[0];
//Reset
for ($i=1;$i<$localityMax+1;$i++)
{
$localityData["id"][$i] = NULL;
$localityData["name"][$i] = "Error";
}
//Assign table to array
for ($i=1;$i<$localityMax+1;$i++)
{
$row = mysql_fetch_assoc($localityResult);
$i = $row["id"];
$localityData["id"][$i] = $row["id"];
$localityData["name"][$i] = $row["name"];
}
//Output
for ($i=1;$i<$localityMax+1;$i++)
{
echo $i.". ";
echo $localityData["id"][$i]." - ";
echo $localityData["name"][$i];
echo "<br />\n";
}
Thanks for the help all!
Primary keys must be unique in MySQL, so you would get a maximum of one possible blank ID since MySQL would not allow duplicate data to be inserted.
If you were working with a column that is not a primary or unique key, your query would need to be the only thing that would change:
SELECT id, name FROM localities WHERE id != "";
or
SELECT id, name FROM localities WHERE NOT ISNULL(id);
EDIT: Created a new answer based on clarification from OP.
If you have a numeric sequence that you want to keep unbroken, and there may be missing rows from the database table, you can use the following (simple) code to give you what you need. Using the same method, your $i = ... could actually be set to the first ID in the sequence from the DB if you don't want to start at ID: 1.
$result = mysql_query('SELECT id, name FROM localities ORDER BY id');
$data = array();
while ($row = mysql_fetch_assoc($result)) {
$data[(int) $row['id']] = array(
'id' => $row['id'],
'name' => $row['name'],
);
}
// This saves a query to the database and a second for loop.
end($data); // move the internal pointer to the end of the array
$max = key($data); // fetch the key of the item the internal pointer is set to
for ($i = 1; $i < $max + 1; $i++) {
if (!isset($data[$i])) {
$data[$i] = array(
'id' => NULL,
'name' => 'Erorr: Missing',
);
}
echo "$i. {$data[$id]['id']} - {$data[$id]['name']}<br />\n";
}
After you've gotten your $localityResult, you could put all of the id's in an array, then before you echo $localityDataStuff, check to see
if(in_array($i, $your_locality_id_array)) {
// do your echoing
} else {
// echo your not found message
}
To make $your_locality_id_array:
$locality_id_array = array();
foreach($localityResult as $locality) {
$locality_id_array[] = $locality['id'];
}

Categories