I've two 3 variable and that used in $sql string
$bikeid = xxxxx
$st_char = column name
$st_tab = table name
I've coded out like this
$sql = "select $st_char
from $st_tab
where bike_id like '$bike_id'";
And like this
$sql = "select ".$st_char."
from dbo.".$st_tab."
where bike_id like ".$bike_id;
To select data from my database,the result is the same,they can get data from database
My question is which one is right and which one is wrong
if none wrong which one is better and why ?
Thanks
Both are bad because they are vulnerable to SQL injection.
There are also potential performance gains from using prepared statements. So at the very least, your query should look like:
select $st_char from $st_tab where bike_id like :bike_id
Unfortunately, you can't use parameters in certain situations, like column and table names. In this case you will need to do manual string concatenation, but whitelist allowed input. For example:
$allowed_cols = array('col1', 'col2', 'col3');
$allowed_tables = array('t1', 't2', 't3');
if(in_array($st_char, $allowed_cols, true) && in_array($st_tab, $allowed_tables, true))
{
$query = "select $st_char from $st_tab where bike_id like :bike_id";
// perform execution here
}
else
{
// invalid or malicious input
}
You may also want to wrap the table/column names in square brackets ([]) to avoid conflicts with any reserved keywords:
$query = "select [$st_char] from [dbo].[$st_tab] where bike_id like :bike_id";
Related
I can't understand what is wrong with this query.
For example: From table names I want to get all records which match string Hound, like hound, Hound 1.2.3, HoundChat, hound version 5.0.2.6, HOUND ver.7.4.4(1536).
Also, string I'll get from $nameid which is associated with column name in table names.
$files = mysql_query("SELECT * FROM names WHERE name LIKE '$nameid%'") or die(mysql_error());
$i=1; while($row=mysql_fetch_array($files)) {
echo "<a href=\"/files/$row[1]\>";
$i++;
UPDATE:
I've get success with
$nameid= substr($_GET['name'],0,5);
Which get only 5 characters from variable and works for me.
Try as below :
$files = mysql_query("SELECT * FROM names WHERE name LIKE '".$nameid."%'") or die(mysql_error());
I assume from your question $nameid is a variable which will have the value hound. You just need to handle the case-insensitive aspect of your query.
Also, You should use prepared statements to prevent sql injection, for example with PDO:
$st = $db->prepare("SELECT * FROM names WHERE name COLLATE UTF8_GENERAL_CI LIKE ?");
$st->execute(array($nameid.'%'));
See explanation of the COLLATE part of the statement here.
I have a variable, $ids
It is a , separated string so it can be $ids = "1" or $ids = "1, 3, 7, 8"
What i want to do is update the database based on these values so i have :
$query = "UPDATE Fields SET Value = '1' WHERE Id IN '$ids'";
And also:
$query = "UPDATE Fields SET Value = '1' WHERE Id '$ids'";
What is the best way to update the database, should i split the string in to an array, and then do a for each loop? or is there a better way?
Save the fact that it's wide open to SQL Injection, this line works for one or many id's:
$query = "UPDATE Fields SET Value = '1' WHERE Id IN ($ids)";
Now, to keep yourself from SQL Injection attacks, which is obviously up to you, you'd want to explode that array and send multiple update statements like this:
$query = "UPDATE Fields SET Value = '1' WHERE Id = :Id";
There's nothing inherently wrong with using an IN clause here. Any WHERE clause works for an UPDATE statement. You'll just want to treat the numbers as a list of values instead of a string. Something like this:
$query = "UPDATE Fields SET Value = '1' WHERE Id IN ($ids)";
The really important part is how you get the $ids value into the query in the first place. You don't show that in the question, but you'll want to make sure you're not opening yourself to a SQL injection vulnerability. Make sure you're properly sanitizing inputs and using prepared statements. How prepared statements handle lists of values vs. individual values is up to the data access technology being used.
Use this query:
$query = "UPDATE Fields SET Value = '1' WHERE Id IN ($ids)";
Where $ids should be formatted als 1,2,3,4. Don't forget to check them before execution (SQL Injection).
I have a function that's like
function getInfoById($id, $info) {
}
the idea is to have a query be "SELECT $info FROM table WHERE id = $id"
This doesn't work with PDO because you can't escape column names. I also don't really want to use "SELECT *" because doesn't that return a bigger result set and use more memory?
Yes, PDO does not have a builtin function for delimiting identifiers like table names and column names. The PDO::quote() function is only for string literals and date literals.
For what it's worth, when I worked on Zend Framework, I implemented a quoteIdentifier() function.
You're right that SELECT * fetches all columns, likely using more memory and spoiling the benefit of covering indexes.
My recommendation is to create an allowlist column names. That is, make sure $info actually names a column of table. Then you don't need to worry about the column name not existing, or containing a strange character, or anything. You get to control the set of columns that are legitimate to put in the query.
You should also delimit the column name anyway. Delimited identifiers are necessary if the column name contains punctuation, whitespace, international characters, or matches an SQL reserved word. See Do different databases use different name quote?
function getInfoById($id, $info) {
// you can make this a literal list, or query it from DESC or INFORMATION_SCHEMA
$cols = array('col1', 'col2', 'col3');
if (array_search($info, $cols) === false) {
return false;
}
$sql = "SELECT `$info` FROM table WHERE id = :id";
$stmt = $pdo->prepare($sql);
if ($stmt === false) {
return false;
}
. . .
}
I show more examples of allowlisting in my presentation SQL Injection Myths and Fallacies or my book SQL Antipatterns, Volume 1: Avoiding the Pitfalls of Database Programming.
I would just filter it out with some regex. Keep it simple.
Also, you should bind $id and have it be :id
$info = preg_replace('/[^A-Za-z0-9_]+/', '', $info);
$stmt = $pdo->prepare('SELECT $info FROM table WHERE id = :id');
$stmt->bindParam(':id', $id);
$stmt->execute();
What about using quote and substr.
$sql = 'SELECT * FROM table WHERE `' . substr($db->quote($field), 1, -1) . '` = :id';
This will remove the quotes surrounding the escaped field.
I have a table with 4 record.
Records: 1) arup Sarma
2) Mitali Sarma
3) Nisha
4) haren Sarma
And I used the below SQL statement to get records from a search box.
$sql = "SELECT id,name FROM ".user_table." WHERE name LIKE '%$q' LIMIT 5";
But this retrieve all records from the table. Even if I type a non-existence word (eg.: hgasd or anything), it shows all the 4 record above. Where is the problem ? plz any advice..
This is my full code:
$q = ucwords(addslashes($_POST['q']));
$sql = "SELECT id,name FROM ".user_table." WHERE name LIKE '%".$q."' LIMIT 5";
$rsd = mysql_query($sql);
Your query is fine. Your problem is that $q does not have any value or you are appending the value incorrectly to your query, so you are effectively doing:
"SELECT id,name FROM ".user_table." WHERE name LIKE '%' LIMIT 5";
Use the following code to
A - Prevent SQL-injection
B - Prevent like with an empty $q
//$q = ucwords(addslashes($_POST['q']));
//Addslashes does not work to prevent SQL-injection!
$q = mysql_real_escape_string($_POST['q']);
if (isset($q)) {
$sql = "SELECT id,name FROM user_table WHERE name LIKE '%$q'
ORDER BY id DESC
LIMIT 5 OFFSET 0";
$result = mysql_query($sql);
while ($row = mysql_fetch_row($result)) {
echo "id: ".htmlentities($row['id']);
echo "name: ".htmlentities($row['name']);
}
} else { //$q is empty, handle the error }
A few comments on the code.
If you are not using PDO, but mysql instead, only mysql_real_escape_string will protect you from SQL-injection, nothing else will.
Always surround any $vars you inject into the code with single ' quotes. If you don't the escaping will not work and syntax error will hit you.
You can test an var with isset to see if it's filled.
Why are you concatenating the tablename? Just put the name of the table in the string as usual.
If you only select a few rows, you really need an order by clause so the outcome will not be random, here I've order the newest id, assuming id is an auto_increment field, newer id's will represent newer users.
If you echo data from the database, you need to escape that using htmlentities to prevent XSS security holes.
In mysql, like operator use '$' regex to represent end of any string.. and '%' is for beginning.. so any string will fall under this regex, that's why it returms all records.
Please refer to http://dev.mysql.com/doc/refman/5.0/en/pattern-matching.html once. Hope, this will help you.
Alt A below is a statement from a php-mysql tutorial. It works as it should.
I found the id-value rather obfuscated and tested alt B. This also worked!
What is the point with the id-value of alt A?
MySQL 5.0.51, PHP 5.2.6
// Alt A :
$sql = "SELECT * FROM example WHERE id = '".$q."'";
// Alt B :
$sql = "SELECT * FROM example WHERE id = $q";
This are just two different approaches to building a string from static and variable data.
Alternative A uses concatenation, or the joining of string and variable tokens using the concatenation operator.
Alternative B uses variable expansion, wherein the variables inside a double-quote-delimited string are expanded to their values at evaluation time.
Neither is necessarily better or preferred, but if you have to have single-quote-delimited strings, for example, then you would need to use alternative A.
Of course, neither of these is preferable to building SQL queries with bound parameters, as not doing so leaves you vulnerable to SQL injection attacks.
Theres two reasons to use the example in 'Alt A'. First is if the string is enclosed in single quotes '', the variable's name will be used in the string instead of it's value.
$id = 7;
'SELECT * FROM table WHERE id = $id' //works out to: WHERE id = $id
"SELECT * FROM table WHERE id = $id" //works out to: WHERE id = 7
Secondly, it's useful to combine strings with the results of a function call.
"SELECT * FROM table WHERE id = '".getPrimaryId()."'"
Outside of what has already been said I've found it best practice, if I'm writing a query, to write it as so:
$sql = "SELECT * FROM table WHERE uid=" . $uid . " LIMIT 1";
The reason for writing SQL like this is that 1. MySQL query doesn't have to parse the PHP variables in the Query and 2 you now easily read and manage the query.
When PHP communicates with MySQL, it is actually (in essence) two languages communicating with each other. This means that a string will be processed by the first language before being sent to the other. It also means that it is important to think in terms of the receiving language
In this case:
$q = 'some_name';<br/>
$query = "SELECT * FROM exempel WHERE id = $q";<br/>
you are telling MySQL to
"SELECT * FROM example1 WHERE id = some_name.
In this case:
$q = 'some_name';<br/>
$query = "SELECT * FROM exempel WHERE id = '$q'";<br/>
and this case:
$q = 'some_name';<br/>
$query = "SELECT * FROM exempel WHERE id = '".$q."'";<br/>
you are telling MySQL to
"SELECT * FROM example1 WHERE id = 'some_name'.
The first example should cause an error as some_name is not a valid part of a MySQL query (in that context). On the other hand, the next two will work fine, because MySQL will look for the String "some_name".
You can also do this:
$sql="SELECT * FROM exempel WHERE id = {$q}";
which is useful for setting off things like:
$sql="SELECT * FROM exempel WHERE id = {$row[id]}";
in 'alt B', $q must be an int or float or other numeric
in 'alt A', $q can be anything a string, int, etc.
The single quote makes that possible. It's just hard to see sometimes if you are looking at it for the first time.