Pointless SQL vs PHP if - php

I need to manipulate entries in a mySQL table using code like this
foreach($items as $item)
{
$sql = "UPDATE `siteims` SET refs = refs + 1 WHERE imid = '{$item->img}';";
$sql .= "UPDATE `lists` SET refs = refs + 1 WHERE lid = '{$item->lili}'";
$dbh->exec($sql);
}
There may be as many as 50 items in $items. A variation on this code would be
foreach($items as $item)
{
if ('z' != $img->img)
$sql = "UPDATE `siteims` SET refs = refs + 1 WHERE imid = '{$item->img}';";
if ('z' != $item->lili)
$sql .= "UPDATE `lists` SET refs = refs + 1 WHERE lid = '{$item->lili}'";
$dbh->exec($sql);
}
In both cases I am executing a sequence of SQL statements for EACH item in $items. My questions
Would it not be a whole lot more efficient to build $sql for items and then execute it?
But then if all of the, potentially, 50 items in $items produces meaningful SQL would that not mean a very slowly executing batch of SQL statements?
Finally, is it better to perform PHP side if tests as in the second version of my code or just build the SQL and let mySQL deal with the fact that the WHERE test returns an empty row?
I'd much appreciate any help with this.

You could use an in clause, instead, e.g.
$sql = "UPDATE .... WHERE imid IN (" . implode($array_that_has_the_ids) . ")"
and reduce yourself down to just one single SQL query. However, this can fail if you're trying to use a HUGE aray - the generated query could exceed the max_allowed_packet setting and get killed.
As for your strlen... what's the point of comparing strlen results against 'z'? strlen returns an integer, you might as well be doing if (apple == orange) instead.

At first place I advice you to use IN clause and just 2 separated queries...
You may have to escape those 2 elements $item->img and $item->lili ..
$ids = array("siteims"=>array(), "lists"=>array());
foreach($items as $item)
{
$ids['siteims'][] = "'" . $item->img . "'";
$ids['lists'][] = "'" . $item->lili . "'" ;
}
if(!empty($ids['siteims'])){
$sql = "UPDATE `siteims` SET refs = refs + 1 WHERE imid IN (".implode(',', $ids["siteims"]).")";
$dbh->exec($sql);
}
if(!empty($ids['lists'])){
$sql = "UPDATE `lists` SET refs = refs + 1 WHERE lid IN (".implode(',', $ids["lists"]).")";
$dbh->exec($sql);
}

Related

PHP + MySQL "WHERE ... IN" doesn't work

I build my query like this:
foreach($ids as $key => $idi) {
$ids[$key] = "'" . $idi . "'";
};
$ids_imploded = implode(", ", $ids);
$sql = "SELECT record_id, email FROM `actions_attendees` WHERE `action_id` IN (" . $ids_imploded . ") AND `backup` = 1 ORDER BY `timestamp` ASC LIMIT " . count($ids) . ";";
$result = mysqli_query($con, $sql);
Where $ids is just array of few numbers (so the $ids_imploded = "'132', '165'").
When I run the generated query in phpMyAdmin, I get what I want. When I run it from PHP, it returns just object with nulls. Why?
I doesn't work neither if I remove the escaping loop.
EDIT: generated query is echoed like
SELECT record_id, email FROM `actions_attendees` WHERE `action_id` IN ('1614', '1615') AND `backup` = 1 ORDER BY `timestamp` ASC LIMIT 2;
The problem could be that you are querying the wrong database, try select a db first, try executing this before the query :
mysql_select_db('yourdb');
Is the result of your query true ? Check your connection object, it seems like you are not on the right database.
It appears that the query was indeed working even in PHP, but later when I was processing the results, intellisense tricked me and I was using mysql_fetch_assoc instead of mysqli_fetch_assoc...

update certain table column if else query

I'm trying to write a query to check which column to update. The user sends an action which they performed (a like or a comment) and I'm trying to update a table. Is it possible to check inside the query which column to update? For example:
DB structure:
id imageName imageLikesCount imageCommentsCount
$actionPerformed = "like";
mysqli_query($link, "UPDATE table (if $actionPerformed=like SET imageLikesCount+1
else imageCommentsCount+1)
WHERE imageName='$image'");
I'm not sure how to phrase that, if it's possible at all. Any advice? Thanks in advance!
though meverhart913 has a way to do it, the better way to do the same thing is to instantiate your variable based on the if condition, then just plug that variable into your string. This keeps you from having to repeat your string over and over as well as allows you to easily add additional conditions.
if($actionPerformed=="like"){
$col = imageLikesCount;
else{
$col = imageCommentsCount;
}
mysqli_query($link, "Update table SET '$col' = '$col + 1' where imageName = '$image'");
if($actionPerformed=="like"){
mysqli_query($link, "Update table SET imageLikesCount = imageLikesCount + 1 where imageName = '$image'");
}
else {
mysqli_query($link, "Update table SET imageCommentsCount = imageCommentsCount + 1 where imageName = '$image'");
}
I'm not a php programmer so my syntax won't be correct, but here are two ways to do it:
if ($actionPerformed == "like")
query for updating imageLikesCount
else if ($actionPerformed == "comment")
query for updating imageCommentsCount
else
whatever
Or
if ($actionPerformed == "like")
$column = "imageLikesCount";
else ($actionPerformed == "comment")
$column = "imageCommentsCount";
$sql = "update table set $column = $column + 1";
Then execute it.

Need help refactoring my redundant code (using MySQL/PHP to populate/build 3 select lists)

I have a meal/recipe database, used for creating daily meal plans. I need to create 3 different select lists (breakfast, lunch, dinner) to display the available recipe options, for each meal_name.
As of now I'm using separate queries for each of the above, and separate builds to display the results for each list.
The query for Lunch:
// Lunch options
$sql = "SELECT plan_date,
plan_meal,
plan_recipe,
recipe_name,
recipe_serving_size
FROM recipe_plans
LEFT JOIN $table_meals ON meal_id = plan_meal
LEFT JOIN $table_recipes ON recipe_id = plan_recipe
WHERE plan_date = '".$date."'
AND meal_name = 'Lunch'
AND plan_owner = '".$user_name."'
ORDER BY recipe_name";
$rc = $DB_LINK->Execute($sql);
DBUtils::checkResult($rc, NULL, NULL, $sql);
// Scan the rows of the SQL result
while (!$rc->EOF) {
$recipeList[($rc->fields['plan_recipe'])] = $rc->fields['recipe_name'] . " (" . $rc->fields['recipe_serving_size'] . ")";
$rc->MoveNext();
}
and the build:
// Scan the fields in the SQL result row
// Print all existing Meals, and some new ones
$minShow = 1;
$maxShow = 1; // only build 1 while testing
for ($i = 0; $i < (isset($MealPlanObj->mealplanItems[$date]) && ($i < $maxShow) ? count($MealPlanObj->mealplanItems[$date]) : 0) + $minShow; $i++) {
if ($i < (isset($MealPlanObj->mealplanItems[$date]) ? count($MealPlanObj->mealplanItems[$date]) : 0)) {
// If it is an existing meal item, then set it
$meal = $MealPlanObj->mealplanItems[$date][$i]['meal']; // meal_id
$servings = $MealPlanObj->mealplanItems[$date][$i]['servings'];
$recipe = $MealPlanObj->mealplanItems[$date][$i]['id']; // recipe_id
} else {
// It is a new one, give it blank values
$meal = NULL;
$servings = $defaultServings;
$recipe = NULL;
}
// The HTML Code to build the select list for 'Lunch'
}
The above code has been duplicated for each meal_name, because that's where my limited skills have left me, lol.
The question is: rather than writing a separate select and build statement for each of the 3 conditions (breakfast, lunch, dinner), how can I write just 1, to output them all?
You already used variables to build the SQL query, so you can introduce just another variable like $meal_name. This variable you can apply to your SQL statement. Instead of:
$sql = "SELECT mplan_date,
...
AND meal_name = 'Lunch'
...
you will write then:
$meal_name = 'Lunch';
...
$sql = "SELECT mplan_date,
...
AND meal_name = '" . mysqli_real_escape_string($meal_name) . "'
...
Note the use of the function mysqli_real_escape_string(), although not absolutely necessary in this example, it's very important to escape all variables you add to an SQL statement, if you are not absolutely sure what's inside the variable. Your example code is vulnerable to SQL-injection.
After that you can go a step further and pack the code into a function:
function buildSqlQuery($meal_name, $date, $user_name)
{
$sql = "SELECT mplan_date,
...
ORDER BY recipe_name";
return $sql;
}
$sqlForBreakfast = buildSqlQuery('Breakfast', '2000-01-01', 'teddy');
$sqlForLunch = buildSqlQuery('Lunch', '2000-01-01', 'teddy');
$sqlForDinner = buildSqlQuery('Dinner', '2000-01-01', 'teddy');

Getting the 100 most recent DB entries from SQL DB via PHP

I'm very new to php/SQL (1 day) so forgive me if I am doing this in a backwards way.
This php below is intended to return the 100 most recent entries into the DB. I attempt to do it by selecting 100 entries to be returned and sort by the date(time stamp) the entry was made. Will this return the 100 more recent entries to the DB? Or am I understanding this wrong?
$type = isset($_GET['type']) ? $_GET['type'] : "global";
$offset = isset($_GET['offset']) ? $_GET['offset'] : "0";
$count = isset($_GET['count']) ? $_GET['count'] : "100";
$sort = isset($_GET['sort']) ? $_GET['sort'] : "date DESC";
// Localize the GET variables
$udid = isset($_GET['udid']) ? $_GET['udid'] : "";
$name = isset($_GET['name']) ? $_GET['name'] : "";
// Protect against sql injections
$type = mysql_real_escape_string($type);
$offset = mysql_real_escape_string($offset);
$count = mysql_real_escape_string($count);
$sort = mysql_real_escape_string($sort);
$udid = mysql_real_escape_string($udid);
$name = mysql_real_escape_string($name);
// Build the sql query
$sql = "SELECT * FROM $table WHERE ";
switch($type) {
case "global":
$sql .= "1 ";
break;
case "device":
$sql .= "udid = '$udid' ";
break;
case "name":
$sql .= "name = '$name' ";
break;
}
$sql .= "ORDER BY $sort ";
$sql .= "LIMIT $offset,$count ";
$result = mysql_query($sql,$conn);
if(!$result) {
die("Error retrieving scores " . mysql_error());
}
//echo $result;
$rows = array();
while($row = mysql_fetch_assoc($result)) {
$rows[] = $row;
}
This should work, although date is a MySQL keyword, so you would either need to enclose date in backquotes or rename that column.
Also, definitely make sure you've sanitized those inputs before building your query. Building a query off of user-editable values from $_GET or $_POST with no sanitation is very unsafe.
For WHERE parameters, you should be running mysql_real_escape_string() on those (which I see you are, I'm not sure if you were before or not). That's enough because you're wrapping those values in quotes in your query, and since you're escaping that string, any attempt to break out of those quotes won't work.
For the stuff like the ORDER BY you have, I would define a valid "list" of allowed values and check to make sure your parameter is in that list. For example:
$valid_orderbys = array('`date` DESC', '`date` ASC', '`name` DESC', '`name` ASC');
if (in_array($_GET['sort'], $valid_orderbys))
{
// you're good, you can use this value
}
else
{
// unexpected value, either alert the user or
// use a default value you define
}
Or for LIMIT, you could use PHP's built-in is_numeric() to verify that the value you're being given is a number, not a crafted string.
It's not enough to simply escape the $table, ORDER BY and LIMIT parameters because they're not wrapped in quotes and therefore someone can just maliciously inject a value of ; DROP TABLE whatever; --. This ends up making your query something like:
SELECT * FROM ; DROP TABLE whatever; --WHERE ...
Queries are separated by semicolons, so there are three queries here. The first fails because it's invalid, the second succeeds in dropping the table, and the third is just a comment so nothing happens. But you can see, if you let users throw whatever they want as one of those parameters, it's a wide open security hole. (I'm not sure if enclosing the table name in backquotes helps this, someone let me know if you know. But in any case, you can do the same attack on the LIMIT and ORDER BY parameters.)
If you have a unique, auto-increment ID for each record (as you should), it would be more efficient to ORDER BY id DESC.
Actually, you already got it right. You should only look into specifying the columns instead of using *.

How to update sql like this?

Hey,i've got a problem, i want to execute this sql update, but it doesn't work. Could anyone help me? Thanks!
The code:
$temp = $_GET['ul'];
foreach ($temp as $key=> $value)
{
$str=array();
$arr=explode(',',$value);
$str =array($key=>$arr);
for($i=0;$i<count($str[$key]);$i++)
{
$tripID='2';
$sql = "UPDATE places_trips
SET orderNo='$i', ColumnNo='$key'
WHERE place_id=" . $str[$key][$i] . "
AND trip_id=" . $tripID;
mysql_query($sql);
}
}
}
I want to set the $tripID = 2, but actually, $tripID=2222. So how to make the $tripID=2 all the time?
Your query doesn't change trip_id. It tries to change orderNo and ColumnNo for rows where trip_id is 2. If I understand you correctly, you should put it in the first part of your query:
"UPDATE places_trips SET orderNo = '$i', ColumnNo = '$key', trip_id = $tripID WHERE place_id = ".$str[$key][$i];
That being said, read about SQL injections. You need it because your current code is terribly dangerous.
I hope this is what you're after:
UPDATE places_trips SET
orderNo = $i,
ColumnNo = $key
WHERE place_id = $str[$key][$i]
AND trip_id RLIKE '^2+$';
Should update all rows where trip_id contains only 2s.
Also search on StackOverflow for SQL Injections, your code is vulnerable to them.

Categories