sql update statement where 2 condition apllies - php

This is quite a basic question, but have not found that much on-line to support.
I need to use a simple update statement in mysql (I know i should use mysqli but not yet ready for this update)
Given That I am working with a database made of a fixed number of items I want that the update apllies only when 2 conditions together are true.
my idea is something like
$sql ="update `members` set `description`='$description[$index]' WHERE id='1' AND fruit = 'banana'";
Is this the proper way of selecting the record to be updated?
Many thanks
Manu

That's how you'd do it more or less, here's a refined one:
$sql ="update `members` set `description`=? WHERE `id`='1' AND `fruit` = 'banana'";
1) See how I put the ? instead of the array? There are smart objects in PHP (read about "Prepared Statements") which allow you to put a parameter "spot" in the query and later have a value instead of it. This makes your query much more secure.
2) I added '`' around your columns. It's not mandatory, but it makes sure that your columns aren't mistaken for something else.

Yes that should work but it's safer to wrap array values in a string in brackets:
$sql ="UPDATE `members` SET `description`='{$description[$index]}' WHERE id='1' AND fruit = 'banana'";
Also make sure $description is somehow filtered or validated, before plugging it directly into the string.
NOTE: Best practice dictates that you use all caps for all SQL keywords, allowing easier differentiation between keywords and your values. Yours has half and half update and set lowercase; WHERE and AND caps, which is worse than going with all lowercase.
[edit] I agree with Daniel Saad that you should be using prepared statements here as well.

Related

Use PHP UPDATE with SET as a variable set to another variable?

Im wondering if something like this is possible?
$joinguild = "UPDATE guild SET '.$rank.'='.$receiver.' WHERE name ='"$dupecheckinfo["guild"]"'";
Im trying to SET '.$rank.'='.$receiver.', but I dont know if I can use a variable where $rank is. Is there a proper way to write this. Is it even possible? If not how would you approach it? Thanks!
Here is my SQL table im working with
Edit: See how my table has Rank1 Rank2 Rank3 etc. Well I am passing the rank value that I want to set so for example
$rank = $_POST["rank"];
$joinguild = "UPDATE guild SET '.$rank.'='.$username.' WHERE name ='"$dupecheckinfo["guild"]"'";
Your question in not clear but you have some problems in your PHP statement. I think you are trying to create your SQL UPDATE query using PHP variables.
Try this:
$joinguild = "UPDATE guild SET $rank='$receiver' WHERE name='" . $dupecheckinfo["guild"] . "'";
Here $rank should have valid column name in your table. Also read about SQL injection.
Your question is quite unclear but to update records from a table you can use this line of code:
$sql=mysqli_query($conn, "UPDATE `table` SET option1='$op1', option2='$op2', option3='$op3', option4='$op4' where id='$id'");
If this is unclear please let me know.
Yes, you can use variables for table and field names in your queries. However, you should avoid it whenever possible, because it generally leads to SQL injection vulnerabilities. Instead of building queries with string concatenation, use prepared statements with bound parameters. See this page and this post for some good examples.
Unfortunately, the bind mechanism works only for values and not for table names or field names, so it's best to try avoiding variable table/field names. If you find that you absolutely must, the best approach would be to ensure that the contents of the variable matches with a pre-set whitelist of allowed table/field names.

SQL update with multiple criteria

I know this is quite simple but I've been looking at this for awhile and can't seem to identify what the issue is. I want to update a row in a table using two criteria. When I use either criteria, the table updates fine but when I combine them, it doesn't work.
This is the query
$updatequery = "UPDATE query SET audio='$finalpath' WHERE content='$title' AND WHERE userid LIKE '%$regID%'";
An example of the reg id:
APA91bGHS59rrpM0sbX9PIYT3SzXs-W1yEtGa2xGMGJXi8O1vW2SrgN7koHDj2o6ZwKvkd3TxtzhktsiVtQNSYQRa4uNDF7Yy0VOf0BJfQOnJWMtN2WBQjmVDsuU-0GxmceNLd8SWqOM
An example of content :
Where can I find a car
You only need to use the where keyword once:
$updatequery =
"UPDATE query SET audio='$finalpath' WHERE content='$title' AND userid LIKE '%$regID%'";
# "WHERE" removed here ------------------------------------^
Mandatory comment:
Using string manipulation like this leaves your code vulnerable to SQL-injection attacks. You should really consider using prepared statements instead.
WHERE content='$title' AND userid LIKE '%$regID%'
Where is needed only once
You can have only one WHERE clause, so this is a syntax error:
WHERE content='$title' AND WHERE userid LIKE '%$regID%'
Combine the logic in a single clause:
WHERE content='$title' AND userid LIKE '%$regID%'
The WHERE clause essentially works like conditionals in any other language. You can build up as complex a tree of boolean conditions as you like, as long as the whole thing resolves down to a boolean then it's fine.
Your query is wrong.
Try this:
$updatequery = "UPDATE query SET audio='$finalpath' WHERE content='$title' AND userid LIKE '%$regID%'";
EDIT:
Where is needed only once.

Hack prepare statement (read first)

I have this code:
<?php
$table = $_GET ["table"];
$query = "SELECT 1 FROM $table";
$st = $pdo->prepare($query);
$st->execute();
This is not the real code, but it is an example to get the idea.
If I make:
hacked.php?table=users;DROP TABLE users;
It will work, cause it is not correctly escaped.
However, if I want to update information like this:
hacked.php?table=users; UPDATE users SET name="abc" WHERE name="def";
It will not work, cause since it is escaped, pdo will convert the query to
SELECT 1 FROM users; UPDATE users SET name=\"abc\" WHERE name=\"def\";
and obviously it fails.
Is there anyway to make this query works?
EDIT 1
We have one guy in our team only devoted to check my code and hacked it. So I want to be ready if this can be in some way accomplished.
EDIT 2
I was already read this: Are PDO prepared statements sufficient to prevent SQL injection? but it really did not answered my question. However it gave me a way to go through. And the solution of #duskwuff was the same I came to. So, for the admins, if this should be removed or marked as a duplicate is ok. But I insist that this can be helpful for someone to know how pdo prepared can be hacked.
It will not work, cause since it is escaped, pdo will convert the query to
SELECT 1 FROM users; UPDATE users SET name=\"abc\" WHERE name=\"def\";
This is incorrect! PDO does not perform escaping on text that is interpolated into queries, as it has no awareness of what text was interpolated. What you're seeing is the result of PHP's deprecated magic_quotes feature adding backslashes to the content of request variables (like $_GET and $_POST). Even if this is enabled, it can be trivially avoided in a query like this one by using non-quoted constructs such as:
SELECT 1 FROM users; UPDATE users SET name = CHAR(97,98,99) WHERE name = CHAR(100,101,102)
(CHAR() is a MySQL function which constructs a string from a list of character code values. If you're using some other database, an equivalent function probably exists.)
Interpolating unescaped content directly into a query is never safe. Don't do it.
I think you are asking the wrong question. If you have code that is even remotely similar to this, then you have a huge problem with the way you're writing code... and probably with the way you're conceptualizing the problem that you need to solve, or you're working from a very bad design.
If, for some reason, you have a need for anything about the design of your database to be passed in on a URL query string or an http post, and if, for some reason, you think executing an unescaped query is the approach you need... then whatever you're doing, you're doing it wrong.
If, by some remote chance, you actually have a need to pass the name of a table to a web page, then the very least you must do is compare the input value to some kind of static structure to see if the input value is in the list... and then use the value from the list, or from something static, never from the input.
Simplistically something as primitive as the following would be a far superior approach, though arguably it is a bad design if table names, column names, or any database internals ever need to go out into browser-land.
$table = $_GET ["table"];
IF ($table == "users")
{
$query = "SELECT 1 FROM users;"
}
ELSEIF ($table == "points")
{
$query = "SELECT 1 FROM points;"
}
...

Most efficent way of determing if a value is in a table

I often run into the situation where I want to determine if a value is in a table. Queries often happen often in a short time period and with similar values being searched therefore I want to do this the most efficient way. What I have now is
if($statment = mysqli_prepare($link, 'SELECT name FROM inventory WHERE name = ? LIMIT 1'))//name and inventory are arbitrarily chosen for this example
{
mysqli_stmt_bind_param($statement, 's', $_POST['check']);
mysqli_stmt_execute($statement);
mysqli_stmt_bind_result($statement, $result);
mysqli_stmt_store_result($statement);//needed for mysqli_stmt_num_rows
mysqli_stmt_fetch($statement);
}
if(mysqli_stmt_num_rows($statement) == 0)
//value in table
else
//value not in table
Is it necessary to call all the mysqli_stmt_* functions? As discussed in this question for mysqli_stmt_num_rows() to work the entire result set must be downloaded from the database server. I'm worried this is a waste and takes too long as I know there is 1 or 0 rows. Would it be more efficient to use the SQL count() function and not bother with the mysqli_stmt_store_result()? Any other ideas?
I noticed the prepared statement manual says "A prepared statement or a parametrized statement is used to execute the same statement repeatedly with high efficiency". What is highly efficient about it and what does it mean same statement? For example if two separate prepared statements evaluated to be the same would it still be more efficient?
By the way I'm using MySQL but didn't want to add the tag as a solution may be non-MySQL specific.
if($statment = mysqli_prepare($link, 'SELECT name FROM inventory WHERE name = ? LIMIT 1'))//name and inventory are arbitrarily chosen for this example
{
mysqli_stmt_bind_param($statement, 's', $_POST['check']);
mysqli_stmt_execute($statement);
mysqli_stmt_store_result($statement);
}
if(mysqli_stmt_num_rows($statement) == 0)
//value not in table
else
//value in table
I believe this would be sufficient. Note that I switched //value not in table
and //value in table.
It really depends of field type you are searching for. Make sure you have an index on that field and that index fits in memory. If it does, SELECT COUNT(*) FROM <your_table> WHERE <cond_which_use_index> LIMIT 1. The important part is LIMIT 1 which prevent for unnecessary lookup. You can run EXPLAIN SELECT ... to see which indexes used and probably make a hint or ban some of them, it's up to you. COUNT(*) works damn fast, it is optimized by design return result very quickly (MyISAM only, for InnoDB the whole stuff is a bit different due to ACID). The main difference between COUNT(*) and SELECT <some_field(s)> is that count doesn't perform any data reading and with (*) it doesn't care about whether some field is a NULL or not, just count rows by most suitable index (chosen internally). Actually I can suggest that even for InnoDB it's a fastest technique.
Also use case matters. If you want insert unique value make constrain on that field and use INSERT IGNORE, if you want to delete value which may not be in table run DELETE IGNORE and same for UPDATE IGNORE.
Query analyzer define by itself whether two queries are the same on or not and manage queries cache, you don't have to worry about it.
The different between prepared and regular query is that the first one contains rule and data separately, so analyzer can define which data is dynamic and better handle that, optimize and so. It can do the same for regular query but for prepared we say that we will reuse it later and give a hint which data is variable and which is fixed. I'm not very good in MySQL internal so you can ask such questions on more specific sites to understand details in a nutshell.
P.S.: Prepared statements in MySQL are session global, so after session they are defined in ends they are deallocated. Exact behavior and possible internal MySQL caching is a subject of additional investigation.
This is the kind of things in-memory caches are really good at. Something like this should work better than most microoptimization attempts (pseudocode!):
function check_if_value_is_in_table($value) {
if ($cache->contains_key($value)) {
return $cache->get($value);
}
// run the SQL query here, put result in $result
// note: I'd benchmark if using mysqli_prepare actually helps
// performance-wise
$cache->put($value, $result);
return $result;
}
Have a look at memcache or the various alternatives.

Combining two PHP sql statements into one

I'm after a little help in the quest for cleaner code...
Current code which is working fine. Wondering if I can make it into one SQL statement as opposed to two...
$sql = "INSERT INTO table_a (1,2,3,4) VALUES ('$1','$2','$3','$4');";
$result = mysql_query($sql,$mysql_link);
$id = mysql_insert_id();
$sql2 = "INSERT INTO table_b (1,2,3,4) VALUES ('$id','$5','$6','$7');";
$result2 = mysql_query($sql2,$mysql_link);
How can I combine these two to work within my current php script?
Thanks!
An insert in two different tables is not possible.
If you want to reduce your query count you may have to reconsider your database structure.
As mentioned above, you can't combine them, because inserts are in 2 different tables, although you could write a stored procedure (with necessary parameters) containing both of these queries and call that procedure in PHP instead of writting those statements... It would help to tell the reason you want to do that, because i can't understand if you want to get more compact (reusable) code, or improve the performance of your DB...
When I see another question of this kind, I am always wondering, why noone asks how to combine ALL sql queries of the script into one. All SELECTs, INSERTS, UPDATES. Wouldn't it be logically?
What's the strange desire to combine? What's the point in it? What's wrong in 2 separate queries?
When you eat, do you mix a salad, a soup, a main dish, a drink into one bowl and then consume it? No? Why do you want to put all the queries into same bowl then?

Categories