Variable table name in delete SQL query with PHP's PDO safely - php

I'm trying to create a function that allows me to delete a certain row in a table. I'd like to use the function for a few different tables so when I call the function I would make one of the parameters of the functions the table name. Here's an example of what I'm trying to do:
function delete($conn, $table, $id) {
$stmt = $conn->prepare("DELETE FROM ".$table." WHERE id = :id");
$stmt->bindParam(":id", $id, PDO::PARAM_INT);
$stmt->execute();
if ($stmt->rowCount() > 0) {
return true;
} else {
return false;
}
}
One problem I'm having though is that because the $table variable goes straight into the SQL Query, wouldn't my database be under risk of SQL Injection?
As I learnt from one of my other questions, I can't just put :table and add it to the bindParam function, so I don't know how to make this function safe. Any ideas??

Sanitize the table data
You can define an array of whitelisted table names to use in your function:
$whitelist = array('table1', 'table2', ...)
and then use:
$myTable= array_intersect_keys($table, array_flip($whitelist));
$myTable will now be safe.

Table names as metadata are much more restricted than row data - so sanitizing a table name should be much more reliable than sanitizing data. By this I ofcourse mean sanitizing outside of PDO.
What we use quite often is a PHP include, that contains all valid table names as an array definition, so we just look it up - if it is not found, and the file age of the include is more than an hour, we run "SHOW TABLES" and recreate the include, so it's quite automagic.

MySQL doesn't currently support dynamic SQL string building, but you could try a whitelist of tables or possibly a MySQL prepared statement with PDO's prepared statements (redundant, I know).
$sql = "
PREPARE stmt FROM
'DELETE FROM #tbl WHERE id = :id';
EXECUTE stmt USING :table;
";
$stmt = $db->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->bindParam(':table', $table);
This is untested, but may help.

Related

select id from table where it equals to row name

I am trying to store the id of a username which I got from $_SESSION to a variable but I can't get the SQL statement to work. The usernames are stored in a database called users and have an ID as primary key. Can someone tell me how I can correct this? Thanks
$name = $_SESSION['username']; //get username of user currently logged in
$rid = $db->exec("SELECT id FROM users WHERE username = '$name'");
From the PHP documentation on PDO::exec():
PDO::exec() does not return results from a SELECT statement. For a SELECT statement that you only need to issue once during your program, consider issuing PDO::query(). For a statement that you need to issue multiple times, prepare a PDOStatement object with PDO::prepare() and issue the statement with PDOStatement::execute().
This means that you cannot use exec() on a SELECT query - instead, you must use query() or prepare(). For any queries using variables or user-input, use prepare() and placeholders in the query for variables, like below, to protect your database against SQL-injection.
$stmt = $db->prepare("SELECT id FROM users WHERE username = :name");
$stmt->execute(["name" => $name]);
if ($row = $stmt->fetch()) {
// $row holds the id
} else {
// No rows were returned at all! No matches for $name
}
Now $row holds the id(s) if the query returned any result at all. Depending on your fetch-type, it might be $row['id'], $row[0], $row->id or a combination of these.
If you expect more than one result, you need to loop while ($row = $stmt->fetch()), or use $stmt->fetchAll();
http://php.net/manual/en/pdo.exec.php
How can I prevent SQL injection in PHP?

SELECT ? FROM table WHERE id = ? not working correctly [duplicate]

This question already has answers here:
Can PHP PDO Statements accept the table or column name as parameter?
(8 answers)
Closed 6 years ago.
I've got a little question. I want to get specific information out of my database via mysqli query:
public function get_searchorder_single_information($soid, $information) {
global $mysqli;
$stmt = $mysqli->prepare("SELECT ? FROM pr_hr_searchorders WHERE id = ?");
$stmt->bind_param('si', $information, $soid);
$stmt->execute();
$stmt->bind_result($result);
$stmt->fetch();
echo $result;
$stmt->close();
}
In my example, $information is set 'job', but it can have other values, too (e.g. 'salary'). When I try to use my query with this variable, echo outputs just 'job' and not the value that is saved in my database. When I write 'job' instead of the '?', echo outputs the correct value.
So now I could make a function for each information I search, but this would end in spaghetti code. So I ask you if there is any possibility to use my search query like above with correct output. How would I do that?
Thanks in advance and sorry for my bad english writing.
Read documentation : http://php.net/manual/en/mysqli.prepare.php
The markers are legal only in certain places in SQL statements. For
example, they are allowed in the VALUES() list of an INSERT statement
(to specify column values for a row), or in a comparison with a column
in a WHERE clause to specify a comparison value. However, they are not
allowed for identifiers (such as table or column names), in the select
list that names the columns to be returned by a SELECT statement, or
to specify both operands of a binary operator such as the = equal
sign. The latter restriction is necessary because it would be
impossible to determine the parameter type. It's not allowed to
compare marker with NULL by ? IS NULL too. In general, parameters are
legal only in Data Manipulation Language (DML) statements, and not in
Data Definition Language (DDL) statements.
Modify your code :
$stmt= $mysqli->prepare("SELECT $information FROM pr_hr_searchorders WHERE id = ?");
$stmt->bind_param('i', $soid);
Change your code to
public function get_searchorder_single_information($soid, $information) {
global $mysqli;
$query = "SELECT".$information." FROM pr_hr_searchorders WHERE id = ?"
$stmt = $mysqli->prepare($query);
$stmt->bind_param('si', $soid);
$stmt->execute();
$stmt->bind_result($result);
$stmt->fetch();
echo $result;
$stmt->close();
}
Then you will get the desired result

how to get multiple rows from a table using SLIM framework

this is my select command
$stmt = $this->conn->prepare("SELECT id,task FROM tbl_all_task WHERE status = 0");
(there are multiple rows having status ).
i tried $stmt->fetchall() , $stmt->fetchall() etc. Nothing works.
I need all rows so that i could make a JSON ARRAY and return this to mu function call.
after you use prepare(), you get a chance to make a 'prepared statement',
and bind values to your query (see bindValue()):
Many of the more mature databases support the concept of prepared statements. What are they? They can be thought of as a kind of compiled template for the SQL that an application wants to run, that can be customized using variable parameters.
after you prepare and (optionally) bind, you must execute();
after which, if every thing went right, you can use fetching methods such as fetchAll().
try it like this:
$stmt = $this->conn->prepare("SELECT id,task FROM tbl_all_task WHERE status = 0");
$stmt->execute();
if ($data = $stmt->fetchAll()) {
print_r(json_encode($data));
}
if you're not interested in a prepared statement (altough it is generally the prefered way), you can just use the query() method directly:
$stmt = $this->conn->query("SELECT id,task FROM tbl_all_task WHERE status = 0");
if ($data = $stmt->fetchAll()) {
print_r(json_encode($data));
}

How to reuse a prepared statement parameter in mysql

I have a (semi) simple MySQL query that I'm trying to use (via php mysqli extension), and I can't quite figure out how to do this.
My query looks like
SELECT DISTINCT Col1 from `table1` where `col2`= ? and `col3`=?
UNION SELECT DISTINCT Col1 from `table2` where `col2`=(?) and `col3`=(?)
I have two tables that I don't want to deal with merging and I just want to reuse the original two prepared "?"s. I know there is something I can do for this when inserting values into a table, but my efforts in searching the docs have thus far proved useless.
Can I do this, and how?
update
Here's my code
$query='SELECT DISTINCT enginesizecc FROM `table1` where year=? and vehicle_make= ? as UNION SELECT DISTINCT enginesizecc from `table2` WHERE year=(?) AND vehicle_make =(?)';
$stmt=$sql->prepare($query);
echo $sql->error; //I'm in debug mode
$blank='';
if(array_key_exists('year', $_POST)){
if(array_key_exists('make', $_POST)){
$stmt->bind_param('ss', $_POST['year'], $_POST['make']);
}
else $stmt->bind_param('ss', $_POST['year'], $blank);
}
elseif(array_key_exists('make', $_POST)){
$stmt->bind_param('ss', $blank, $_POST['make']);
}
else{
//if(array_key_exists('model', $_POST)) $stmt->bind_param('sss', $blank, $blank);
$stmt->bind_param('ss', $blank, $blank);
}
$stmt->execute();
$modelItem='';
$stmt->bind_result($modelItem);
$models=array();
while($stmt->fetch()){
$models[]=$modelItem;
}
sort($models);
return $models;
I know that I could just bind the same variables twice, but that seems rather inefficient.
PDO allows you to name parameters specifically, like so, but MySQLi doesn't support named variables:
"SELECT x FROM y WHERE name = :name and key = :key"
In PDO this would let you re-use :name and :key after specifying their types. I'm not arguing over which is better, since you can achieve the same thing in MySQLi.
The thing is that MySQLi makes it rather hard to stick to the "Don't Repeat Yourself (DRY)" methodology. (Consider custom functions if you like DRY).
It's the reason some prefer PDO over MySQLi, but there are some funky workarounds (such as call_user_func_array in custom functions, etc).
And as to your "efficiency" comment, it really makes no difference to repeat the variables. It will be parameterized in the MySQL API call twice, but it hardly affects performance significantly. PDO parameterizes internally without using MySQL (unless you explicitly make it use MySQL), and MySQLi makes the MySQL API parameterize for it.
Here is an example on how to bind parameters to a query.
global $dbconnection;
$sql = "INSERT INTO Sales(order_id,client_id,sale_date,status) VALUES (?,?,?,?)";
if ($stmt = $dbconnection->prepare($sql))
{
/* Bind our params */
$stmt->bind_param('iisi',$order_id,$client_id,$today,$status);
$stmt->execute();
$stmt->close();
}
else
{
print "ERROR";
}

How to create a prepared statement in PHP with a formula involving columns in the where clause?

I want to create prepared stmt such as
"SELECT id,latitude,longitude
FROM sometable WHERE
(3437.74677 * ACOS(SIN(latitude_radians) * SIN(?) +
COS(latitude_radians)*COS(?) * COS(longitude_radians - ?))) <= ?";
in PHP. Where clause is a function of column values and bind variables
but how should I bind the values. Or is this even a legal prepared stmt?
Thanks in advance,
-v-
I don't see any problem here.
See:
PHP Prepared Statements.
Extremely minimal sample:
$stmt = $dbh->prepare( $QUERY );
$stmt->execute( $arguments_array )
Sorry for being unclear.
As I understand following is an example of PHP prepared stmt,
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name'])))
Now the where clause is always a simple, column = ? AND column2 = ?. In my case though its function and it didnt work when assigned values to the bind variables. I will regenerate the error again and post it.
I was wondering then if it is even legal to have a function of column names and bind variables in the where clause.

Categories