Reputation: 580
I'm having trouble with this snippet of code, and can't find any errors:
$query = "CREATE TABLE ? (? INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(?), ? VARCHAR(30), ? VARCHAR(50), ? TIMESTAMP, ? VARCHAR(50), ? DECIMAL(15, 2), ? DECIMAL(3, 2), ? VARCHAR(255))";
$array = array($table_name, $id, $id, $a_title, $c_title, $date_updated_title, $s_title, $ds_title, $ps_title, $u_title);
try {
$results = db_query($db, $query, $array); // db_query() is my PDO function to query the database. This function works fine elsewhere.
echo($table_name . " create successfully!");
} catch (PDOException $e) {
echo('<br />Could not create table "' . $table_name . '".');
return false;
error($e); //error() is my function to write errors to my log, and works fine elsewhere.
}
When I run this in my browser, it returns my caught exception 'Could not create table "name".' However, I don't see any error in my log, so I don't know if it's a syntax issue, or what.
When I take the query itself, and replace the question marks with the actual values, and dump it in PHPMyAdmin, it creates the table fine. I'm not really sure what the issue is here. I've had reasonable success with PDO on another site, but I'm still relatively new. Any ideas?
Thanks for the help!
[Edit] I've since tried using this query:
"CREATE TABLE $a_title (? INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(?), ? VARCHAR(30), ? VARCHAR(50), ? TIMESTAMP, ? VARCHAR(50), ? DECIMAL(15, 2), ? DECIMAL(3, 2), ? VARCHAR(255))";
I've tried with both single and double quotes. I also removed the $table_name variable from the array. Still getting a syntax error, and not sure why.
Upvotes: 2
Views: 160
Reputation: 562310
Comment from @DCoder is correct. You can use a query parameter only in place where you could normally put a single string literal, date literal, or numeric literal.
You can't use a query parameter for:
Table names
WRONG: SELECT * FROM ?
Column names
WRONG: SELECT * FROM table WHERE ? = 1234
Lists of values
WRONG: SELECT * FROM table WHERE column IN (?)
Though you could use IN()
with a list of parameter placeholders, one for each scalar value.
SQL operators, expressions, or keywords
WRONG: SELECT * FROM table WHERE column ? 'value' AND ? ORDER BY column ?
For those cases, if you want dynamic content to become part of your query, the content must be part of the query before you call prepare()
.
But this means that you're back to interpolating variables into SQL query strings, which we are told is a no-no for its SQL injection risk.
The solution is to use filtering and whitelisting to make sure that the content doesn't contain some unsafe content. For example, if it's a dynamic table name, strip out anything but characters you know you want to keep, and then also delimit the table name just in case someone names their table a reserved word like "table" or "order" or something.
$table = preg_replace("/[^\w]/", "", $table);
$sql = "CREATE TABLE `{$table}` ( ... )";
Re your comment:
Yes, column names are off limits as well. As I said at the top, parameters are only for scalar values.
You also need to learn the appropriate usage of the three different types of quote marks.
Upvotes: 2