How do I query a database with php using bind variables? - php

I'm making a song database system, and I'm trying to implement a way for users to search songs based on a category to search (song's name, artist's name, album name, genre etc) and a given search term. To accommodate user input and protect against SQL injection, I'm using a prepared statement made with bind variables, however I'm having trouble with what I currently made:
search("genre", "electropop", $db);
function search($column, $term, $db) {
try {
$sql = "SELECT * FROM Songs WHERE :column=:term;";
$stmt = $db->prepare($sql);
$params = array("column" => $column,
"term" => $term);
$stmt->execute($params);
$arr = $stmt->fetchALL(PDO::FETCH_ASSOC);
print (json_encode($arr));
}
catch(PDOException $ex) {
catch_error("The search failed.", $ex);
}
}
Whenever I test this, I get an empty array back: [ ]
I tested my query ("SELECT * FROM Songs WHERE genre='electropop'") in phpmyadmin and it checks out (gave me back entries).
The correct syntax for WHERE clauses in SQL is that the term needs to be surrounded by quotations (https://www.w3schools.com/sql/sql_where.asp) so I tried escaping quotation marks around the term:
...
$sql = "SELECT * FROM Songs WHERE :column=\':term;\'";
...
But then it fails to even see :term as a token to bind variables to later.
Not sure how to go about solving this. I assumed the empty array is due to a valid search but just no results, but perhaps I'm not correctly using a prepared statement. Any help would be much appreciated! Thanks!

You missed the : before term param. Don't need to bind column name. Just use the $column var instead of :column.
search("genre", "electropop", $db);
function search($column, $term, $db) {
try {
$sql = "SELECT * FROM Songs WHERE $column=:term;";
$stmt = $db->prepare($sql);
$params = array(":term" => $term);
$stmt->execute($params);
$arr = $stmt->fetchALL(PDO::FETCH_ASSOC);
print (json_encode($arr));
}
catch(PDOException $ex) {
catch_error("The search failed.", $ex);
}
}

Related

How do you stop injection in this PHP/PDO

So I have look at so many post, web sites and video and now I am so confused! I can't seem to get it right.
How do you stop injection in this PHP/PDO. I have this code that works, but it allows injection.
//*THIS WORKS BUT ALLOWS INJECTION
//*
//The variable $word comes from another php file where the search is created.
public function getAllCards($word) {
$sql = "SELECT * FROM carddbtable WHERE businessNameDB='".$word."'";
foreach ($this->conn->query($sql) as $row) {
echo json_encode($row)."<br>"."<br>";
}
$db = null;
}
With this new code I am trying to remove the variable "$word" from the "SELECT * FROM " statement
to stop the injection and add the "prepare" and the error checking and the "execute" statement, but I can't get it right. How would I do this? FYI this is a GoDaddy shared server.
//Getting the search "word" from the GetCards.php
public function getAllCards($word) {
//Empty var to store all returned info from db
$returnArray = array();
// sql statement to be executed
$sql = "SELECT * FROM carddbtable WHERE businessNameDB=':word";
// prepare to be executed
$statement = $this->conn->prepare($sql);
// error occurred
if (!$statement) {
throw new Exception($statement->error);
}
// execute statement
$statement->execute( :word => '$word' );
//run the query
foreach ($this->conn->query($statement) as $row) {
echo json_encode($row)."<br>"."<br>";
}
// store all appended $rows in $returnArray to be sent to app
$returnArray[] = $row;
}
You've almost got it. PDO, like many database drivers, will be responsible for all of the escaping, so just leave the placeholder as plain as possible:
$sql = "SELECT * FROM carddbtable WHERE businessNameDB=:word";
No ' necessary there.
Now when you execute() a PDO statement you get a result which you need to capture into a variable:
$res = $statement->execute([ 'word' => $word ]);
As Ibu and chris85 point out the '$word' part is also incorrect. Avoid quoting single variables, it's not only pointless, it can cause trouble, like here where you're binding to literally dollar-sign word, not the value in question. This goes doubly for "$word".
Then you fetch from that. Right now you're calling query() on the statement, which is incorrect.
Another thing to note is kicking the habit of making throw-away variables like $sql as these are just junk. Instead pass the argument directly:
$statement = $this->conn->prepare("SELECT * FROM carddbtable WHERE businessNameDB=:word");
This avoids accidentally mixing up $sql3 with $sql8 if you're juggling a bunch of these things.
This is what i have now.
//Getting the search "word" from the GetCards.php
public function getAllCards($word) {
//Empty var to store all returned info from db
$returnArray = array();
// prepare to be executed sql statement to be executed if not entered word
$statement = $this->conn->prepare("SELECT * FROM carddbtable WHERE businessNameDB=:word");
// error occurred
// if (!$statement) {
// throw new Exception($statement->error);
// }
// execute statement
$res = $statement->execute([ 'word' => $word ]);
//run the query
foreach ($this->conn->query($res) as $row) {
echo json_encode($row)."<br>"."<br>";
}
// store all appended $rows in $returnArray to be sent to app
$returnArray[] = $row;
}
I got this working
//*FUNCTION TO GET CARD FROM SEARCH WORD CALLED FROM GetCards.php
public function getAllCards($word) {
//Connect to db using the PDO not PHP
$db = new PDO('mysql:host=localhost;dbname=xxxx', 'xxxx', 'xxxx');
//Here we prepare the SELECT statement from the search word place holder :word
$sql = $db->prepare('SELECT * FROM carddbtable WHERE businessNameDB=:word');
//We execute the $sql with the search word variable"$word"
$sql->execute([':word' => $word]);
//Looping through the results
foreach ($sql as $row)
//Print to screen
echo json_encode($row). "<br>"."<br>";
}

PHP PDO & SQL Search wildcard bind parameters

I am trying to create a search function for a site and have created the sql code, which was generated from PHPMYADMIN, see below;
$sql = "SELECT * FROM `bg85ow`.`sessions` WHERE CONVERT(`SessionName` USING utf8) LIKE '%:SessionName1%'";
Here is the PHP code processing the query;
//bind params
$SessionName1 = filter_input(INPUT_GET, 'search');
$stmt -> bindValue(':SessionName1', $SessionName1, PDO::PARAM_STR);
//execute
$success = $stmt -> execute();
if (!$success){
print $stmt->errorInfo()[2]; //PDO driver error message
}
else{
}
//array
$r = $stmt->fetchAll(PDO::FETCH_ASSOC);
$dbh = null;
if(!$r)
{
echo "No Results";
}
foreach ((array) $r as $row) {
echo $row['SessionId'];
echo $row['SessionName'];
}
For some reason this will not return any results the execute part is working fine and passing the success test but then once it gets to the array it returns no results.
I checked and $SessionName1 has the term in it from search so it is being passed to the query ok.
When I change the %:SessionName1% to football which is the search term I am testing with, the code returns the results fine but once changed back to :SessionName1 it will not return the results even though the search term is exactly the same.
Can anybody see what I am doing wrong, I spent ages looking at this and cannot see the error.
I have searched everywhere for an answer to this but I couldn't find one specific to this issue, also I am a beginner with PHP and SQL.
Try this Example : Check where is you are wrong.
// Get the keyword from query string
$keyword = $_GET['keyword'];
// Prepare the command
$sth = $dbh->prepare('SELECT * FROM `users` WHERE `firstname` LIKE :keyword');
// Put the percentage sing on the keyword
$keyword = "%".$keyword."%";
// Bind the parameter
$sth->bindParam(':keyword', $keyword, PDO::PARAM_STR);

Having trouble with PDO Prepared Statement and "LIKE"

So, first off, I know there are certain rules you have to follow when preparing a LIKE statement with PDO. I have already looked these up and I'm trying my best to follow them, but the query consistently returns no results even though I know the query itself is legitimate (MySQL command line client works correctly with the query).
This is for a school project; I need to make a website with a MySQL/php backend for a fictional bookstore.
I have a class in a php script called DBConnection. It is in a separate namespace (hence the backslashes for PDO objects and functions). This is part of it:
<?php
class DBConnection {
// ...
public function prepAndExecute($sql, $args) {
try {
$stmt = $this->conn->prepare($sql);
for($i = 1; $i <= count($args); $i++) {
$stmt->bindValue($i, $args[$i-1], \PDO::PARAM_STR);
}
$stmt->execute();
return $stmt;
} catch(\PDOException $e) {
return false;
}
}
}
?>
The actual MySQL query I am trying to run:
SELECT ISBN, Title, Author, Price FROM Book WHERE Title LIKE "%rich%";
My attempt at using a PDO Prepared Statement to run this on the website:
<?php
// based on the search form from the previous page
// (all values are set correctly by the form, already tested)
$criteria = $_POST["searchCriteria"]; // "Title" (from a <select> element)
$term = $_POST["searchTerm"]; // "rich" (from the text box)
$conn = new DBConnection(); // uses namespace correctly, just didn't
// include here for simplicity
$sql = "SELECT ISBN, Title, Author, Price FROM Book WHERE ? LIKE ?";
$stmt = $conn->prepAndExecute($sql, array($criteria, "%" . $term . "%"));
// I have also tried $term = "%" . $term . "%", still no luck
echo $stmt->rowCount(); // 0
?>
I ran the above query in the MySQL command line, and got 1 result as expected. I know the class/functions work because I use that same function to run all other SELECT and INSERT queries, and have had no problems until I try to run this LIKE statement.
Am I doing something wrong? Because I double and triple checked everything and could have sworn I was doing this right.
http://php.net/manual/en/pdostatement.bindparam.php
$sth = $dbh->prepare('SELECT * FROM `users` WHERE `firstname` LIKE :keyword');
// Put the percentage sing on the keyword
$keyword = "%".$keyword."%";
// Bind the parameter
$sth->bindParam(':keyword', $keyword, PDO::PARAM_STR);

Updating a MySQL database via PDO and tokens - all parameters being set to last value in dataset

As the title states: I am trying to update specific records in a MySQL data base using PDO and tokens to secure against any injection.
Here is my code:
Some arrays to help build the query:
$id = 1234
$values = array ('a','b','c',);
$variables = array ($A, $B, $C);
The query built via loop:
$sql = "UPDATE table1 SET ";
foreach($values as $value)
{
$sql .="$value = :$value, ";
}
$sql = rtrim($sql,', ');
$sql .=" WHERE id = '$id'";
Execution of query via PDO:
try
{
$pdo = new PDO('mysql:host=localhost; dbname=db01', $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare($sql);
foreach(array_combine($values, $variables) as $value=>$variable)
{
$stmt->bindParam(":$value", $variable);
}
$stmt->execute();
The result:
Every field in the specified record (matching $id) is set to the same value, which is always equal to the contents of the last variable listed in the array (in this example they would all contain the value held in $C)
echoing the SQL query shows it has been constructed correctly.
Any ideas? Thanks for your consideration
Extending from comment:
In your foreach loop, the $variable is a value, not a reference, so when you mysqli_stmt::execute(), you actually end up using the last $variable.
To avoid that, you'll have to use something like this:
$cache=array_combine($values,$variables);
foreach($cache as $value=>$variable)
{
$stmt->bindParam(":$value",$cache[$value]);
}
You have to make this way:
foreach(array_combine($values, $variables) as $value=>$variable)
{
$stmt->bindParam(":$value", $variable);
$stmt->execute();
}
Execute your query inside the for loop. Don't execute your query once the loop is done because it will only get the last value of your array. It will only execute once.

what's wrong with this single PDO?

Here the thing, other PDO works well, but this one doesn't. I have tried with
execute(array(':t'=>$table));
with no success. Ideas?.
public function __construct($table){
try{
$pdocnx = new PDO("mysql:host=localhost;dbname=sigcat",'root','');
$stmt = $pdocnx->prepare('select * from sigcat.:t');
$stmt->bindParam(':t', urldecode($table), PDO::PARAM_STR,45);
$stmt->execute();
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($row);
}catch(Exception $e){
echo $e->getMessage();
}
}
I got many records in 'supplies' but it returns array(0) { }. I'm getting the 'table' parameter with $_GET['table']. No exceptions though.
You can't bind table names, only values.
Maintain a list of valid names and ensure the string is present in the valid list.
If you can't build a list of valid names, you are probably doing something wrong.
You can't bind tables, so you can do a sneaky trick like this:
public function myFunction($table){
$st = "SELECT FROM `" . $table ."` ..some sql";
$statement->prepare($st);
$statement->execute();
}
Hope this helps.

Categories