Most efficient way to use arrays in MySQL statements? - php

Alright, take this for example:
$array['key'] = 'value';
$SQL = "SELECT column FROM table WHERE column='{$array[key]}'";
That's how I've been doing it, but of course if I were to enable E_ALL error reporting, I'd get a notice about using the undeclared constant, and it would assume 'key' instead of a constant.
As such, I assume that's not the proper or more efficient way to do it, so what would be the most efficient way of doing that SQL query (or other relevant string)?

Actually, if you lookup the PHP string quoting rules, if you omit the quotes around the key inside {} it will be interpreted as a constant. However, if you omit the {} and the quotes, a simple array index will be properly interpreted without issuing a notice.
PHP double-quoted string parsing rules (The relevant examples are in the Variable Parsing section)
I tend to prefer surrounding with {} for readability:
// Inside {}, you must quote the array key or it will be interpreted as a constant
$SQL = "SELECT column FROM table WHERE column='{$array['key']}'";
But this is also valid and should not issue notices:
// Without {}, don't quote the array key and it will be correctly parsed.
$SQL = "SELECT column FROM table WHERE column='$array[key]'";
Note that the best way to pass variables into SQL queries is to use an API that supports prepared statements instead of concatenating in variables

You need to quote key.
$SQL = "SELECT column FROM table WHERE column='{$array['key']}'";

I always prefer to do it that way:
$SQL = "SELECT column FROM table WHERE column='".$array['key']."'";
and I have never run in trouble with that.
If you re-use the sql, binding would be an advantage:
http://nz.php.net/manual/en/pdostatement.bindparam.php
HTH

Related

Vulnerability to SQL injection even when SQLite3::escapeString() is used and no user input is asked?

I am referring to this answer of mine to another question, which another user criticized because vulnerable to SQL injection, even if no user input is requested and escape procedure is called.
The following code is used to create a .sql dump of an SQLite database, using only PHP code with no call to sqlite3 tool (which was the original request of the author of the question).
<?php
$db = new SQLite3(dirname(__FILE__)."/your/db.sqlite");
$db->busyTimeout(5000);
$sql="";
$tables=$db->query("SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%';");
while ($table=$tables->fetchArray(SQLITE3_NUM)) {
$sql.=$db->querySingle("SELECT sql FROM sqlite_master WHERE name = '{$table[0]}'").";\n\n";
$rows=$db->query("SELECT * FROM {$table[0]}");
$sql.="INSERT INTO {$table[0]} (";
$columns=$db->query("PRAGMA table_info({$table[0]})");
$fieldnames=array();
while ($column=$columns->fetchArray(SQLITE3_ASSOC)) {
$fieldnames[]=$column["name"];
}
$sql.=implode(",",$fieldnames).") VALUES";
while ($row=$rows->fetchArray(SQLITE3_ASSOC)) {
foreach ($row as $k=>$v) {
$row[$k]="'".SQLite3::escapeString($v)."'";
}
$sql.="\n(".implode(",",$row)."),";
}
$sql=rtrim($sql,",").";\n\n";
}
file_put_contents("sqlitedump.sql",$sql);
In the comments to this answer, user #Dharman insisted this code is vulnerable, and after asking to provide a full example of a case of how it could lead to problems, he told me to just open a question regarding the matter.
I personally feel there is no way this code could "explode" because of the contents already present inside the database to be dumped, but I'm no authority.
So I ask you instead.
It's pretty reasonable to name a table Order in an e-commerce application, but this causes a syntax error if you run a query like:
SELECT * FROM Order
Why? Because Order is a reserved keyword in SQLite. It introduces an ORDER BY clause. Using a table named Order in this way just creates a syntax error.
SQLite allows you to name tables after reserved words by delimiting the table name.
This is in the documentation I linked to about reserved words:
'keyword' A keyword in single quotes is a string literal.
"keyword" A keyword in double-quotes is an identifier.
[keyword] A keyword enclosed in square brackets is an identifier. This is not standard SQL. This quoting mechanism is used by MS Access and SQL Server and is included in SQLite for compatibility.
`keyword` A keyword enclosed in grave accents (ASCII code 96) is an identifier. This is not standard SQL. This quoting mechanism is used by MySQL and is included in SQLite for compatibility.
So you can use a table named Order without error like this:
SELECT * FROM "Order"
You shouldn't use SQLite3::escapeString($table[0]) because that's for string literals. Remember from the list above, single-quoted strings are string literals. The escapeString() function only escapes ' characters, so you can put that string inside single-quotes as the delimiter, and thus you can use strings like 'O\'Reilly'.
But escapeString() doesn't do anything for the double-quotes used for delimiting table names. There isn't a function provided for that. So you either have to be sure you have no table names that contain a " character, or else use other PHP functions to escape them.
$safeTable = str_replace('"', '\\"', $table[0]);
$rows = $db->query("SELECT * FROM \"{$safeTable}\"");
You should also read 8. Double-quoted String Literals Are Accepted on this page: https://www.sqlite.org/quirks.html

Why do you need a specific syntax to insert data into postgresql

I have found a way to insert data into a postgresql database using php. Therefore, I used the following syntax:
$sql = "INSERT INTO genes
(id,gene,plasmid,accessionnumber,plasmidname)
VALUES ('".$var_id."','".$var_gene."','".$var_ACC."','".$var_PN."')";
Why do you have to use quotes within quotes and adding a point before and after the variable?
The answer on the question is point concatenates your string, quotes you use to separate literal from variables. (Vao Tsun)

Can I use a variable directly inside the echo function without cause any incompatibility?

when I write a query for MySQL, usually use a form like this:
$column= "column_name";
$query = "SELECT * FROM table_name WHERE \"".$column."\"" = \"some_value\" ";
if I want to avoid using the \"". sequence for the variables, can I use this other form or there could be some compatibility issues or some other problem ?
$column= "column_name";
$query = "SELECT * FROM table_name WHERE \"$column\" = \"some_value\";
In both of these cases what you're doing is fine, but a few notes:
1) What you're doing in your first form is using the strings like string literals, which means you can/should use single quotation marks instead of double quotation marks, as they are parsed much faster.
$column = 'column_name';
$query = 'SELECT * FROM table_name WHERE ' . $column . ' = "some_value"';
What you're doing in the second example is also fine, it just depends on the reason you're trying to avoid using the escape character, but if you're just doing it for the sake of readability, what you have is fine.
Worth noting is that handling queries the way you're doing here is getting deprecated and you should take a look at PDO and inject your values that way.
Edit Per Comments Above - Removed " from around the column.
Yes, you can.
Strings delimited with double quotes are interpreted by the PHP parser.
to make sure, the variable is identified correctly, put it into curly brackets
Example
$variable = 1;
$array = array( 1,2 );
$object = new stdclass();
$object->member = 1;
$string = "You can basically put every kind of PHP variable into the string. This can be a simple variable {$variable}, an array {$array[0]} or an object member {$object->member} even object methods.";
If you want PHP to take the $variable literally without interpretation, put the string into single quotes.
Another method I really like to use for queries is the heredoc notation
$sqlQuery = <<< EOQ
SELECT
"field"
FROM
"table"
WHERE
"id" = '{$escapedValue}'
EOQ;
One more note:
In SQL you should delimit values with the single quote, and identifiers like table name and field names with double quotes (ANSI compatible) or the back tick ```

Why is my query finding field entries that are numbers, but not number/letter combinations

Newbie here. The following function works fine when $color refers to an entry in the "style" field that is numberic e.g. "5000". But if the entry is "5000B" or letters entirely, it can't find it. Is this an indexing problem?
function get_shirt_colors_by_style($color)
{
db_connect();
$query = "SELECT style,sanmar_mainframe_color,unique_key,color_square_image
FROM sanmar_products WHERE style=$color
GROUP BY style ORDER BY style";
$result = mysql_query($query);
$data = mysql_fetch_array($result);
return $data;
}
It is failing to find alphanumeric comnbinations because the string is not quoted:
$query = "SELECT style,sanmar_mainframe_color,unique_key,color_square_image FROM sanmar_products WHERE style='$color' GROUP BY style ORDER BY style";
//-----------------------------------------------------------------------------------------------------------^^^^^^^^^
Numeric values need not be quoted in a MySQL query, but string values must always be surrounded in single quotes like '5000B'.
We assume the value of $color has already been escaped against SQL injection:
// Hopefully this happened already.
// If not, do it before running mysql_query()
$color = mysql_real_escape_string($color);
Is this an indexing problem?
No its a really bad coding problem.
Non-numeric values should be enclosed in quotes - actually literal values should always be enclosed in quotes when the underlying column type is numeric - otherwise you're likely to run into performance issues. You've also got a problem with managing errors in your code - if a query containing "WHERE style=5000B" is sent to the database it will always return an error - that you have no visibility of this error means that you've got a lot of important functionality missing from your site. Indeed, since content representations whould always be validated / changed at the point where the value leaves PHP, that also implies that your code is probably wide open to SQL injection attacks.
...and then there's the database design issues evident here: 'style' implies a non-unique identifier yet you are returning a single row from your query without any explicit ordering other than on the field you've selected on (i.e. even if it were unique, its very innefficient).
try using single quotes here:
WHERE style='$color'

MySQL_real_escape_string not adding slashes?

So I do this:
<?php
session_start();
include("../loginconnect.php");
mysql_real_escape_string($_POST[int]);
$int = nl2br($_POST[int]);
$query = "UPDATE `DB`.`TABLE` SET `interests`='$int' WHERE `user`='$_SESSION[user]'";
mysql_query($query) or die(mysql_error());
mysql_close($con);
?>
And let's say that $_POST[int] is "Foo' bar." The single-quote remains unescaped AND I get a MySQL error when running the script, due to the quote. What's wrong?
m_r_e_s() RETURNS the escaped value, it doesn't modify the original.
$int = mysql_real_escape_string($_POST['int']);
$query = "UPDATE ... interests = '$int' ...";
Note that I've added quotes around the int in the POST value. Without the quotes, PHP sees it as a constant value (e.g. define()). If it doesn't find a constant of that name, it politely assumes you meant it to be used a string and adjust accordingly, but issues a warning. If you had done
define('int', 'some totally wonky value');
previously, then you'd be accessing the wrong POST value, because PHP would see it as $_POST[some totally wonky value] instead.
You're not using the results of mysql_real_escape_string in your query.
Try doing this:
$int = nl2br(mysql_real_escape_string($_POST[int]););
You should be using prepared statements. It has a slight learning curve over mysql_* functions, but is well worth it in the long run.
You should quote your strings, like $_POST['int'] instead of $_POST[int].
At the top of your file put error_reporting(-1);

Categories