PHP continue causing infinite loop - php

I've got a weird little problem.
I'm writing a script that inserts multiple rows into a MySQL DB, quirk is that their IDs are not necessarily a nice neat 1,2,3 set as they're being edited. The continue statement must be skipping every row as it times out in PHP. This has been doing my head in for the past few hours. Any ideas?
Thanks!
$items = $_POST['invItemQuantity'];
$i = 1;
while($i <= $items) {
if(!isset($_POST['item'.$i])) continue;
//assign posts to variables
$date = $_POST["item_date".$i];
$description = $_POST["description".$i];
$price = $_POST["price".$i];
$ID = $_POST["item".$i];
$que = "UPDATE invoice_items SET date='".$date."', description ='".$description."', price ='".$price."' WHERE item_ID=".$ID;
$test .= $que."<br>";
$i++;
}

if(!isset($_POST['item'.$i])) continue;
You forgot to increment i in that case. Fix it to :
if(!isset($_POST['item'.$i])) { $i++; continue; }

Since you need to iterate over all the item fields no matter what, a for loop might make it easier to not forget your increment action.
$items = $_POST['invItemQuantity'];
for($i=1; $i<=$items; $i++)
{
if(!isset($_POST['item'.$i])) continue;
// ...
}
You might also want to perform some validation on "$_POST['invItemQuantity']" before you use it in your code (e.g. verify it contains a number of expected range).

Your whole approach to this is very strange. I'm guessing in your form you have item1, item2, item3 etc. Instead you should have items[] for all of them to submit it as an array. Do the same for each item_date, description and price. Then simply run:
foreach($_POST['items'] as $i => $item) {
if(!empty($item)) {
$date = mysql_real_escape_string(trim($_POST['item_date'][$i]));
$description = mysql_real_escape_string(trim($_POST['description'][$i]));
$price = mysql_real_escape_string(trim($_POST['price'][$i]));
$ID = (int)$_POST['item'][$i];
//UPDATE QUERY...
}
}
The other thing is you should never take user input and directly input it into the database as that leaves you wide open to SQL injections. You should always escape it first using mysql_real_escape_string (for mysql). Even better would be to learn MySQLi or PDO.
You may also wish to look at filter_input, a good way to make sure that your inputs are clean. You should never trust user input and should always test it against a white list of suitable variables if possible.

Related

How to get a random row, using RedBeanPHP, from a table, that has gaps in id numbers order?

I'm trying to get a random row from a table using RedBean. I tried this:
$amount = R::count($names);
$id = rand(0, $amount);
$randomname = R::load( $names, $id );
$name = $randomname["name"];
But soon i found that this way is not correct, because the table has gaps in the id numbers order, there can be ids 1-95, then 115-523, then 530-600, etc. There are gaps, because i deleted rows manually, so the random $id falls on these gaps sometimes and never falls on last rows, because the $amount is smaller than the last id.
As i understand after trying to find the answer in others' questions, the id should be left untouched, that means i don't need to try to change the ids themselves so that they won't contain gaps. So i'm trying to make something instead.
I've tried also this, it works, though i think it's too many checks for a single row result:
$randomnames = R::findAll($names);
$a = 0;
foreach($randomnames as $n){
if($a == $id){
$name = $n['name'];
$a = $amount;
}
else $a++;
}
Maybe i should use MySQL's RAND somehow, if there is nothing existing for this in RedBean itself, or R::exec with SQL... How is it the best to get a random row?
I've just started to learn both RedBean and PHP, tried to find an answer myself, also on RedBean's page, but couldn't find something specific for this. Also my first question here, so i hope i asked it correctly. :)
My two cents ;-)
$ids = R::getCol("select id from $names"); //returns an array of id's indexed as 0..number of names-1
$random_index = rand(0, sizeof($ids)-1);
$random_name = R::load( $names, $ids[$random_index] );
$name = $random_name["name"];

update array data to database inside looping

I face a problem with update more then one value with the same name to database.
//while loop
{
<input name="exists[]" value='$row1[Status_Name]'></input>
}
bellow are how I update the data to database
if (isset($_POST["updsts"]))
{
$gid = $_POST["id"];
$sqlq = "SELECT * FROM orderstatus WHERE Status_Group = '$gid'";
$result = mysqli_query($conn, $sqlq);
$rowcount = mysqli_num_rows($result);
if ($rowcount == 0)
echo "No records found";
else
{
$x = '0';
while( $x<$rowcount)
{
$stsname = $_POST["exists[$x]"];
$sqlu = "UPDATE orderstatus SET
Status_Name = '$stsname'
WHERE Status_Group = '$gid'";
$x++;
}
}
My $row1[Status_Name] will show all the status_name inside a table.
You can loop over the post array key:
foreach ($_POST['exists'] as $val) {
// Do your updates here
}
Additionally, this code has a lot of other serious problems you should be aware of.
You're not escaping any data used in the context of HTML. Use htmlspecialchars() around any arbitrary data you're concatenating into HTML. Without this, you risk creating invalid HTML as well as potential security issues with injected scripts.
You're not escaping any data used in your queries! As it stands right now, pretty much anyone can do whatever they want with your database data. Automated bots hit these sort of scripts and exploit them all the time. Use parameterized queries, always. Never concatenate data into the context of a query!
There's no need for this select and then update loop. Just use one update.

Splitting a string of values like 1030:0,1031:1,1032:2 and storing data in database

I have a bunch of photos on a page and using jQuery UI's Sortable plugin, to allow for them to be reordered.
When my sortable function fires, it writes a new order sequence:
1030:0,1031:1,1032:2,1040:3,1033:4
Each item of the comma delimited string, consists of the photo ID and the order position, separated by a colon. When the user has completely finished their reordering, I'm posting this order sequence to a PHP page via AJAX, to store the changes in the database. Here's where I get into trouble.
I have no problem getting my script to work, but I'm pretty sure it's the incorrect way to achieve what I want, and will suffer hugely in performance and resources - I'm hoping somebody could advise me as to what would be the best approach.
This is my PHP script that deals with the sequence:
if ($sorted_order) {
$exploded_order = explode(',',$sorted_order);
foreach ($exploded_order as $order_part) {
$exploded_part = explode(':',$order_part);
$part_count = 0;
foreach ($exploded_part as $part) {
$part_count++;
if ($part_count == 1) {
$photo_id = $part;
} elseif ($part_count == 2) {
$order = $part;
}
$SQL = "UPDATE article_photos ";
$SQL .= "SET order_pos = :order_pos ";
$SQL .= "WHERE photo_id = :photo_id;";
... rest of PDO stuff ...
}
}
}
My concerns arise from the nested foreach functions and also running so many database updates. If a given sequence contained 150 items, would this script cry for help? If it will, how could I improve it?
** This is for an admin page, so it won't be heavily abused **
you can use one update, with some cleaver code like so:
create the array $data['order'] in the loop then:
$q = "UPDATE article_photos SET order_pos = (CASE photo_id ";
foreach($data['order'] as $sort => $id){
$q .= " WHEN {$id} THEN {$sort}";
}
$q .= " END ) WHERE photo_id IN (".implode(",",$data['order']).")";
a little clearer perhaps
UPDATE article_photos SET order_pos = (CASE photo_id
WHEN id = 1 THEN 999
WHEN id = 2 THEN 1000
WHEN id = 3 THEN 1001
END)
WHERE photo_id IN (1,2,3)
i use this approach for exactly what your doing, updating sort orders
No need for the second foreach: you know it's going to be two parts if your data passes validation (I'm assuming you validated this. If not: you should =) so just do:
if (count($exploded_part) == 2) {
$id = $exploded_part[0];
$seq = $exploded_part[1];
/* rest of code */
} else {
/* error - data does not conform despite validation */
}
As for update hammering: do your DB updates in a transaction. Your db will queue the ops, but not commit them to the main DB until you commit the transaction, at which point it'll happily do the update "for real" at lightning speed.
I suggest making your script even simplier and changing names of the variables, so the code would be way more readable.
$parts = explode(',',$sorted_order);
foreach ($parts as $part) {
list($id, $position) = explode(':',$order_part);
//Now you can work with $id and $position ;
}
More info about list: http://php.net/manual/en/function.list.php
Also, about performance and your data structure:
The way you store your data is not perfect. But that way you will not suffer any performance issues, that way you need to send less data, less overhead overall.
However the drawback of your data structure is that most probably you will be unable to establish relationships between tables and make joins or alter table structure in a correct way.

PDO best way to check if 300+ values exist in database

I have a time dependent script I am working on and used microtime() to find the bottle neck. I determined the time increase is caused by doing a check on 300+ values to see if they exist in a database one at a time at 0.04 seconds a query.
The background of the script is it is a caching script. I need to see if it exists in the DB so I need a true/false (obtained by a rowCount) but i also need a way to relate a false to a value so I can update it. I know using a WHERE tag IN (:ARRAY) would work faster than the individual calls, but I cant think of a way to apply an association of true/false to value in this method.
My current code is below:
//loop through all our values!
//prepare out reusuable statement
$stmt = $db->prepare("SELECT * from cache WHERE value=?");
foreach($values as $tempVal)
{
//find if its in the database
try
{
$stmt->execute(array($tempVal));
$valCount = $stmt->rowCount();
} catch(PDOException $ex) {
echo "PDO error send this to us: " . $ex->getMessage();
}
//update flag
$addToUpdate = 1;
//if its in the database
if($valCount > 0)
{
//get the tag data
$valRes= $stmt->fetch();
//check if cache expired
$addToUpdate = 0;
}
//add to update list
if($addToUpdate)
{
//needs updating
$updateList[] = $tempVal;
//add to not in DB list to minimize queries
if($tagTCount == 0)
{
$notInDB[$tempVal] = $tempVal;
}
}
Any suggestions? I can explain more if anything is not clear.
Thank you,
Nick
So you just issue your query with the complete array, using the IN (?,?,?,?,?...) list:
// abstract, use a PDO wrapper of your choosing
$query = db("SELECT * FROM cache WHERE value IN (??)", $values);
Then iterate over the result list. Only matched $values will return. So build your first list from that:
foreach ($query as $row) {
$updateList[] = $row["value"];
}
To get the list of absent entries, just diff that against your original array:
$notInDB = array_diff($values, $updateList);
You could of course use a second NOT IN query. But doing that differentiation in PHP is simpler.

Drupal - db_fetch_array returns NULL for every row

I'm using Drupal's db_fetch_array to fetch rows from my db_query. However, every row returned is equal to NULL. Typing the query into PHP myadmin works, so I have no idea whats going on. db_num_rows returns the number of rows as well. Here is the code:
if(count($rebuild_ids))
{
$ids=implode(",",$rebuild_ids);
$type_stmt = "SELECT * from {" . ItemType::$type_table_name . "} where id IN ($ids)";
$new_items=db_query($type_stmt);
if(!$new_items || db_num_rows($new_items) == 0)
{
return;
}
while($row = db_fetch_array($new_items));
{
if ($row!=NULL)
{
echo "I work!"
$game_items[] = $row['id'];
ItemInstance::$nid_to_item_type_code[$row['nid']] = $row['id'];
}
}
}
However, it never gets into the third if statement (i.e. never echos "I work!") Any ideas?
Friendly advice: Drupal has a coding standards http://drupal.org/coding-standards -- it helps to keep them. This error would have been a lot more obvious that way....
Also putting variables in a query is a huge no-no see http://drupal.org/writing-secure-code
$row is not NULL by definition, otherwise it wouldn´t even reach the third if statement.
There is no need to check if $row contains information, the while loop already takes care of that, but if you want to check anyway, use something like empty($row) or count($row) > 0; don´t compare an array with NULL.
The checking is completely unnecessary though...
K figured it out. It was the semicolon after the while loop!

Categories