bindParam PDO PHP - php

I am having a problem with binding param or value, does anybody knows what wrong?
If i change ? to area it works :-$
$item = 'area';
$query = dbConnectionPDO::getConnect()->prepare( ' SELECT * FROM ? ' );
$query->bindParam(1, $item, PDO::PARAM_STR);
$query->execute();
while($resultId = $query->fetch(PDO::FETCH_ASSOC)){
////
}
Is this a good solution? It works!
$select = 'select * from ' . $item . ' left join ' . $TableName . ' ';
$query = dbConnectionPDO::getConnect()->prepare("$select ON :three = :four");
$query->bindValue(':three', $three, PDO::PARAM_STR);
$query->bindValue(':four', $four, PDO::PARAM_STR);
$query->execute();
while($resultId = $query->fetch(PDO::FETCH_ASSOC)){
////
}

You're trying to bind a table name, not a parameter. I'm not sure you can actually do that.
bindParam works by binding question-mark holders or named parmeters, not a table name.
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < ? AND colour = ?');
$sth->bindParam(1, $calories, PDO::PARAM_INT);
$sth->bindParam(2, $colour, PDO::PARAM_STR, 12);
$sth->execute();
If you're just looking into placeholder "replacement" you can just use sprintf, but be careful since if you'll be doing anything fishy or stupid (like accepting the table name from an external source), it might be leaky.
For example:
$theQ = "SELECT * FROM `%s` LEFT JOIN `%s` ON `%s` = `%s`";
$runQ = sprintf($theQ, 'one', 'two', 'three', 'four');

You need to provide a valid SQL statement where only literals are parametrized. Even if the database driver is dumb enough to accept the query, you'll end up executing something like:
SELECT * FROM 'area'
... which is obviously not what you intended.

You cant parametrize a table name, only parameters.

Related

PDO prepared statement bind parameters once for different queries

I am using PDO prepared statements to execute two queries:
SELECT count(*) FROM vocabulary WHERE `type` = :type AND `lesson` = :lesson;
SELECT * FROM vocabulary WHERE `type` = :type AND `lesson` = :lesson limit 100;
The first query to get the count works as expected and i get the row count.
$stmt = $this->connection->prepare($sql);
foreach ($params as $key => $value)
$stmt->bindValue(":" . $key, $value, PDO::PARAM_STR);
$stmt->execute();
$count = $stmt->fetchColumn();
$sql .= " limit $limit;";
$sql = str_replace("count(*)", $columns, $sql);
$stmt = $this->connection->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_CLASS, $class);
But when executing the second query i get:
SQLSTATE[HY093]: Invalid parameter number: no parameters were bound
Therefore, I would like to know, if I have multiple queries where the parameters are exactly the same ,if I need to bind the same parameters again using
foreach ($params as $key => $value)
$stmt->bindValue(":" . $key, $value, PDO::PARAM_STR);
or if there is a way to bind parameters only once.
If I have multiple queries where the parameters are exactly the same, do I need to bind the same parameters again using
Yes, of course.
Parameters are bound to each query, not to PDO or a database globally.
On a side note, with PDO you don't have to bind variables explicitly, so there is a solution to your "problem": just don't bind at all but send your data directly into execute() as it shown in the Dharman's excellent answer
There is no need to modify your SQL like this. Your code basically comes down to this:
$stmt = $this->connection->prepare('SELECT count(*) FROM vocabulary WHERE `type` = :type AND `lesson` = :lesson');
$stmt->execute($params);
$count = $stmt->fetchColumn();
$stmt = $this->connection->prepare('SELECT * FROM vocabulary WHERE `type` = :type AND `lesson` = :lesson limit 100');
$stmt->execute($params);
$result = $stmt->fetchAll(PDO::FETCH_CLASS, $class);

PDO bindParam not working in IN binding for sql query

I'm trying to get some videos according to some attributes (age, year, countries). For some reason, even though I'm binding parameters to the query properly and have specified the query properly (u.country NOT IN ($countries_count)), I still get results for the country = U.S.A. Is there something work with my bindParam. Please Help.
<?php
$parameters = json_decode(file_get_contents('php://input'), true);
$age = $parameters["age"];
$year = $parameters["year"];
$countries = sizeof($parameters["countries"]) == 0 ? array("0") : $parameters["countries"];
$countries_count = implode(",", array_fill(0, sizeof($countries), "?"));
$sql = "SELECT
v.title, u.name
FROM
video AS v JOIN user AS u ON v.id_user = u.id
WHERE
u.age <= ? AND YEAR(v.upload_date) >= ? AND
u.country NOT IN ($countries_count);";
$connection = new PDO("mysql:host=localhost;dbname=data_base", "root", "");
$statement = $connection->prepare($sql);
$statement->bindParam(1, $age, PDO::PARAM_INT);
$statement->bindParam(2, $year, PDO::PARAM_INT);
foreach ($countries as $k => $x) {
$statement->bindParam($k+3, $x, PDO::PARAM_STR);
}
$statement->execute();
echo json_encode($statement->fetchAll());
?>
Your problem is that you are binding all the IN parameters to the same variable ($x) so they all end up with the same value. You can work around that by either changing to bindValue or by binding to the actual array value I.e.
$statement->bindParam($k+3, $countries[$k], PDO::PARAM_STR);
Change bindParam to bindValue
If you want to use bindParam, change your sql to
u.age <= :age and
YEAR(v.upload_date) >= :year
...
Then bind param:
->bindParam(':age', $age)
->bindParam(':year', $year)

Customize MySql query with PDO

I'm making a function to query my database, fully, with a keyword search ($wordsToSearch) or with some category tags words($tagsToSearch) if there are.
This is my function, and it's not secure since i use the concat to add some part of the query. How should I use PDO to filter the variabiles and then add the part of the query when it is necessary?
Thanks to everybody
$wordsToSearch = " ";
$tagsToSearch = " ";
if(is_string($search)){
$wordsToSearch = "WHERE (
`artist_nm` LIKE '%".$search."%'
OR `place` LIKE '%".$search."%'
)";
}
if(is_string($searchtags)){
$arrayTags = explode(',', $searchtags);
$tagsToSearch = "HAVING (
`tags` LIKE '%".$arrayTags[0]."%' ";
foreach ($arrayTags as $key => $value) {
if($key != 0 && $key <= 20) {
$tagsToSearch .= "OR `tags` LIKE '%".$value."%' ";
}
}
$tagsToSearch .= ")";
}
$database->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$STH = $database->prepare('SELECT id, lat, lng, CONCAT_WS( "/&/", total, tags ) AS data
FROM (SELECT lat, lng, id, CONCAT_WS( "/&/", img_link, artist_nm, page_link, place, Total_Rating, Rating_Number ) AS total, GROUP_CONCAT( tag_name
SEPARATOR "," ) AS tags
FROM images
LEFT OUTER JOIN tbl_places ON images.id = tbl_places.KE_img
LEFT OUTER JOIN rel_tags ON images.id = rel_tags.Id_immagine
LEFT OUTER JOIN tags ON tags.Id_tag = rel_tags.Id_tag
'.$wordsToSearch.'
GROUP BY id '.$tagsToSearch.'
) AS subquery
');
try {
$STH->execute();
} catch(PDOException $e){
echo $e->getMessage();
die();
}
You are looking for prepared requests. You have to put compile your query with some parameters with prepare() method:
<?php
// With placeholders
$sth = $database->prepare('SELECT * FROM table WHERE id = ?');
// With named parameters
$sth = $database->prepare('SELECT * FROM table WHERE id = :id');
?>
Then you can execute the query using execute() method:
<?php
// With placeholders
$sth->bindParam(1, $yourId, PDO::PARAM_INT);
$sth->execute();
// or
$sth->execute(array($yourId));
// With named parameters
$sth->bindParam(':id', $yourId, PDO::PARAM_INT);
$sth->execute();
// or
$sth->execute(array(':id' => $yourId));
?>
Edit:
Of course you can put more than one parameter:
<?php
// With placeholders
$sth = $database->prepare('SELECT * FROM table WHERE username = ? AND password = ?');
$sth->bindParam(1, $username, PDO::PARAM_STR);
$sth->bindParam(2, $password, PDO::PARAM_STR);
$sth->execute();
// or
$sth->execute(array($username, $password));
// With named parameters
$sth = $database->prepare('SELECT * FROM table WHERE username = :username AND password = :password');
$sth->bindParam(':username', $username, PDO::PARAM_STR);
$sth->bindParam(':password', $password, PDO::PARAM_STR);
$sth->execute();
// or
$sth->execute(array(':username' => $username, ':password' => $password));
?>
More information in the documentation.

Why won't this PDOStatement execute properly?

I have other PDO Statements that execute fine, but this one is screwed up.
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT ?,?' );
$sth->execute( array( 0, 10 ) );
The above does NOT work, but the below does work:
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT 0,10' );
$sth->execute( array( 0, 10 ) );
So why won't the first way display any of my results when it should be giving the same response?
So here is what I have now
$start = 0;
$perpage = 10;
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT ?,?' );
$sth->bindValue(1, $start, PDO::PARAM_INT);
$sth->bindValue(2, $perpage, PDO::PARAM_INT);
$sth->execute();
this also does not work
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT ?,?' );
$sth->bindParam(1, 0, PDO::PARAM_INT);
$sth->bindParam(2, 10, PDO::PARAM_INT);
$sth->execute();
The problem is likely that PDO will interpret any inputs as strings. You can try
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT :low,:high' );
$sth->bindValue(':low', 0, PDO::PARAM_INT);
$sth->bindValue(':high', 10, PDO::PARAM_INT);
$sth->execute();
Or
$low = 0;
$high = 10;
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT :low,:high' );
$sth->bindParam(':low', $low, PDO::PARAM_INT);
$sth->bindParam(':high', $high, PDO::PARAM_INT);
$sth->execute();
Source: How to apply bindValue method in LIMIT clause?
Not sure if you saw this question but have you tried casting the values you send as ints?
$start = 0;
$perpage = 10;
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT ?,?' );
$sth->bindValue(1, (int)$start, PDO::PARAM_INT);
$sth->bindValue(2, (int)$perpage, PDO::PARAM_INT);
$sth->execute();
Or it says to do this:
$start = 0;
$perpage = 10;
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT ?,?' );
$sth->bindValue(1, intval($start), PDO::PARAM_INT);
$sth->bindValue(2, intval($perpage), PDO::PARAM_INT);
$sth->execute();
This is because "prepare" and execute with array argument thinks your datas are string by default. So they escape them with ' '. THe problem is that when you deal with limits those quotes trigger error.
The solution is bindValue
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT :number OFFSET :start' );
$sth->bindValue("number",10, PDO::PARAM_INT);
$sth->bindValue("start",0,PDO::PARAM_INT);
$sth->execute();
What database? MySQL? SQL Server? Oracle?
In MySQL the PDO with LIMIT clause should work as in GlaciesofPacis's post. However, if you are using SQL SERVER you're not using the correct syntax. Referenced from StackOverflow question:
$query = "
DECLARE #Sort
SET ROWCOUNT :startRow
SELECT #Sort = SortColumn FROM Table ORDER BY SortColumn
SET ROWCOUNT :pageSize
SELECT ... FROM Table WHERE SortColumn >= #Sort ORDER BY SortColumn
";
$dbh->prepare($query);
$sth->bindParam(':startRow',0, PDO::PARAM_INT);
$sth->bindParam(':pageSize',10, PDO::PARAM_INT);
$sth->execute();

PHP PDO Security

Im trying to work with PDO for the first time and I'm just wanting to know how secure what I'm doing is, I'm also new to PHP.
I have a query that when a user is passed ot my page, the page takes a variable using GET and then runs.
With PHP I've always used mysql_real_escape to sanitize my variables.
Can anybody see security flaws with this?
// Get USER ID of person
$userID = $_GET['userID'];
// Get persons
$sql = "SELECT * FROM persons WHERE id =$userID";
$q = $conn->query($sql) or die($conn->error());
while($r = $q->fetch(PDO::FETCH_LAZY)){
echo '<div class="mis-per">';
echo '<span class="date-submitted">' . $r['date_submitted'] . '</span>';
// MORE STUF
echo '</div>';
}
Don't use query, use prepare:
http://php.net/manual/de/pdo.prepare.php
$userID = $_GET['userID'];
$sql = "SELECT * FROM persons WHERE id = :userid";
$q = $conn->prepare($sql)
$q->execute(array(':userid' => $userID ));
while($r = $q->fetch(PDO::FETCH_ASSOC)){
echo '<div class="mis-per">';
echo '<span class="date-submitted">' . $r['date_submitted'] . '</span>';
// MORE STUF
echo '</div>';
}
The SQL statement can contain zero or more named (:name) or question mark (?) parameter markers for which real values will be substituted when the statement is executed.
With anything you use, it's about how you use it rather than what you use. I'd argue that PDO itself is very safe as long as you use it properly.
$sql = "SELECT * FROM persons WHERE id =$userID";
That's bad *. Better :
$sql = "SELECT * FROM persons WHERE id = " . $conn->quote($userID);
Better :
$q = $conn->prepare('SELECT * FROM persons WHERE id = ?')->execute(array($userID));
* This is bad, and that's because if $userID is "1 OR 1", the query becomes SELECT * FROM persons WHERE id =1 OR 1 which will always return all values in the persons table.
As the comments say: Atm there is no security whatsoever against SQLI. PDO offers you (if the database driver supports it (mysql does)) Prepared Statements. Think of it like a query-template that is compiled/passed to the dbms and later filled with values.
here is an example of usage:
$sql = 'SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour';
//Prepare the Query
$sth = $dbh->prepare($sql);
//Execute the query with values (so no tainted things can happen)
$sth->execute(array(':calories' => 150, ':colour' => 'red'));
$red = $sth->fetchAll();
Adjust as follows (you can use either :userId or simply ? as Tom van der Woerdt suggests, even if I think the first one gives more clearness, especially when there are more than just one parameter):
$sql = "SELECT * FROM persons WHERE id =:userID";
$q = $conn->prepare( $sql );
$q->bindValue( ":userID", $userID, PDO::PARAM_INT ); // or PDO::PARAM_STR, it depends
$q->execute();
$r = $st->fetch();
...
...

Categories