PHP PDO mysql prepared statment and join - php

I have a question.
I have the following query:
$query = "select * from module,bloc where module.id_bloc = ?";
I tried to bind the value so I did:
$stmt = $this->db->prepare($query);
$stmt->bindValue(1, "bloc.id_bloc");
But, when I test I don't get any result on my browser.
It's weird because when I replace directly inside like the following code:
$query = "select * from module,bloc where module.id_bloc = bloc.id_bloc";
I get the the right result on my browser.
Could someone explain to me why it doesn't work when I am doing a bindValue?

It will not work because, when bound, a string will be quoted. (Or, for all intents and purposes, work as if it were quoted, however PDO may handle it behind the scenes.) Then, your query is interpreted as:
select * from module,bloc where module.id_bloc = 'bloc.id_bloc'
That is: It will be interpreted as a literal string, rather than a reference to a table column, and will obviously not give you the expected result. There is no need for binding it to begin with.
If, for some reason, you need to run a query with a variable table/column name from an unsafe source, you will have to manually format/sanitize it; see here for an example of how to do it.

Related

Protect Oracle database against SQL Injection

I'm on Symfony and I don't know how protect my database against sql injection. If you have some idea, I will be gratefull.
My function with sql :
public function getResult($$value)
{
$sql = "SELECT SOMETHING FROM SOMETHING smt
WHERE smt.THING = '".$value."'";
return $this->egee->executeQuery($sql);
}
And here is my executeQuery funciton :
public function executeQuery($sql) {
$entityManager = $this->em->getConnection('xxx');
$stmt = $entityManager->prepare($sql);
$stmt->execute();
return $stmt->fetch();
}
I allready try with BindParam, but it's didn't work with Oracle.
With BindParam I have this response :
Error 503 : Service Unavailable
The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.
Here's how you do it ... with any and every database: parameterized queries.
Your SQL string now becomes:
SELECT SOMETHING FROM SOMETHING smt WHERE smt.THING = ?
Notice the ? (which is not in quotes ... this is not a one-character literal string) This indicates a query parameter.
Now, each time you execute the query, you supply an array() containing each of the parameter-values you want to substitute, in order left-to-right. Different values may be used each time the query is executed (without re-preparing it), because these values are not "part of" the query: they are inputs.
No matter what the parameter-value contains, the database engine will never see it as anything other than the numeric or string value that it is. It will never regard it as "part of the SQL." Thus, SQL-injection becomes impossible.
Furthermore, the [binary] value is used directly, instead of being decoded from a character string. So, say, if you want to use quote-marks as part of your string parameter-value, you would not "encode" them with backslashes. (If you provided \", then "a backslash followed by a quote mark" is what SQL would see as the parameter's value ... a perfectly acceptable two-character value.)
Here's a nice write-up: https://www.w3schools.com/php/php_mysql_prepared_statements.asp
The documentation for Doctrine ORM in the Symfony manual shows an example of using a query parameter:
https://symfony.com/doc/current/doctrine.html#querying-with-sql
$sql = '
SELECT * FROM product p
WHERE p.price > :price
ORDER BY p.price ASC
';
$stmt = $conn->prepare($sql);
$stmt->execute(['price' => $price]);
You don't need to use BindParam. Just pass a hash array to execute(), where the hash keys are the named query parameter placeholders you put in your SQL query.

Understanding PDO Prepared Statements and Binding Parameters

From experience and also having been told constantly the benefits of using prepared statements and binding my parameters, I have constantly used those two techniques in my code, however I would like to understand exactly the purpose of each of those two techiques:
From my understanding of prepared statements:
$sql = "SELECT * FROM myTable WHERE id = ".$id;
$stmt = $conn->prepare($sql);
$stmt->execute();
The previous code should create a sort of a buffer in the database with the query I proposed. Now FROM MY UNDERSTANDING (and I could be very wrong), the previous code is insecure, because the string $sql could be anything depending on what $id actually is, and if $id = 1; DROP TABLE myTable;--, I would be inserting a malicious query even though I have a prepared statement.
FROM MY UNDERSTANDING this is where binding my parameters com in. If I do the following instead:
$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->execute();
The database should know exactly all the parts of the sql statement before hand:
SELECT these columns: * FROM myTable and WHERE id = "a variable that was input by the user", and if "a variable that was input by the user" != a variable, the query fails.
I have been told by some my understanding is correct, and by others that it is false, could someone please let me know if I am wrong, correct, or missing something? And elaborate as much as you want, all feedback is greatly appreciated!
You're correct that the first case is insecure. It's important to understand though, that preparing a statement only has value if you are using variable data, and/or executing the same query repeatedly. If you are executing plain statements with no variables, you could simply do this:
$sql = "SELECT * from myTable WHERE this_column IS NOT NULL";
$result = $conn->query($sql);
And end up with a PDOStatement object to work with, just like when you use PDO::exec().
For your second case, again, you're largely correct. What's happening is the variable passed to the database is escaped and quoted (unless you specify otherwise with the third argument to PDOStatement::bindParam(), it's sent as a string which is fine for most cases.) So, the query won't "fail" if bad data is sent. It behaves exactly as if you had passed a valid number that didn't exist as an ID in the database. There are, of course, some edge cases where you are still vulnerable even with a correctly prepared statement.
Also, to make life easier, you can use prepared statements like this, to do implicit binding:
$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->execute([":id"=>$id]);
Or even like this, with un-named parameters:
$sql = "SELECT * FROM myTable WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->execute([$id]);
Naturally, most of this has been explained in the comments while I was typing up the answer!

Mysqli LIKE not working with apostrophe?

When I use my mysqli function to search the database for a certain string with a ' (apostrophe) it never finds a result, although it is exactly the same in the databse.
For example: I search for: dawn's, this gets escaped through real_escape to: dawn\'s and this is the same as in the database (it's put in escaped as well in the database). But still it does not give me a result.
This is the code I use:
$mysqli = goConnect();
$query = $mysqli->real_escape_string($query);
if(!($stmt = $mysqli->prepare("SELECT * FROM movies WHERE title LIKE '%$query%'"))){
http_response_code(400);
echo "<p class='results'>Cannot prepare the statement, please try again later.</p>";
}
echo $query;
if($stmt->execute()){
Why doesn't this work properly?
Mysqli doesn't have a LIKE operator and Mysql LIKE works with any characters, including apostrophe.
and this is the same as in the database (it's put in escaped as well in the database).
This is what you are doing wrong. It shouldn't be the same in the database. It should be stored as is.
Besides, you should always, always ALWAYS use placeholders to substitute variables in the query. Were you using them, you'd never encounter a problem like this.
So, first change this code to
$mysqli = goConnect();
$stmt = $mysqli->prepare("SELECT * FROM movies WHERE title LIKE ?");
$query = "%$query%";
$stmt->bind_param("s", $query);
$stmt->execute();
And then change your insert code accordingly, to make it add not a single extra character to the data.

query multiple columns php/mysql

new to php and am enrolled on a course, so can ask tutor tomorrow if this is more complicated than i think it might be!
I have an sql query, and it works fine. But I am trying to add and 'and' in the select statement.
This is what I have at the minute
$query = "SELECT * from table1 where table1.age <= " . $_POST['min_age'] ;
I have a 'region' input on my linked html page and want results to be returned only if the min_age and region values match those inputted by the user.
I have tried adding an 'and where' but it doesn't work and I am not sure if it is because of the multiple "'s or if what I am trying to do needs a different method?
Thanks
If you need multiple conditions, just separate them with AND:
... WHERE table1.age <= ? AND table1.region = ?
No need to use WHERE again. Just like you wouldn't need to use if() more than once if you were writing a complex condition in PHP.
PS: This isn't directly related to your question, but you should get into the habit of not putting $_POST or $_GET variables directly into your SQL queries. It's a good way to get hacked! Ask your tutor about "SQL injection," or read my presentation SQL Injection Myths and Fallacies.
I know you're just starting out, but if you were training to be an electrician, you would place a high priority on learning how to avoid being electrocuted or how to avoid causing a fire.
Here's how I would write your query using mysqli. One advantage of using query parameters is you never need to worry about where you start and end your quotes.
$query = "SELECT * from table1 where table1.age <= ? AND table1.region = ?";
$stmt = $mysqli->prepare($query) or trigger_error($mysqli->error, E_USER_ERROR);
$stmt->bind_param("is", $_POST["min_age"], $_POST["region"]);
$stmt->execute() or trigger_error($stmt->error, E_USER_ERROR);
The other good habit I'm showing here is to always report if prepare() or execute() return an error.
If you must interpolate variables into your SQL, first make sure you protect the variables either by coercing the value to an integer, or else by using a proper escaping function like mysqli_real_escape_string(). Don't put $_POST variables directly into the string. Also you don't have to stop and restart the quotes if you use PHP's syntax for embedding variables directly in double-quoted strings:
$age = (int) $_POST["min_age"];
$region = $mysqli->real_escape_string($_POST["region"]);
$query = "SELECT * from table1 where table1.age <= {$age}
AND table1.region = '{$region}'";

Executing a prepared PDO statement with the like clause [duplicate]

This question already has answers here:
How do I create a PDO parameterized query with a LIKE statement?
(9 answers)
Closed 3 years ago.
I am new to PHP, and am trying to learn to use PDO to connect to a test MySQL db. I have the following:
try {
$db = new PDO('mysql:dbname=MYDBNAME;host=MYHOST', 'USERNAME', 'PASSWORD');
$query = "select * from books where ? like '%?%'";
$stmt = $db->prepare($query);
$stmt->execute(array($searchtype, $searchterm));
} catch(PDOException $e) {
echo 'PDOException: ' . $e->getMessage();
}
When I try it I get the following warning:
Warning: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
When I remove the like clause, and the $searchterm param, it returns the result properly. I thought -- like '%?%' -- might not be a legal way to create this query under double quotes, so I tried escaping ', which did not work. I looked around for a solution, and found that someone moved '% and %' down to where $searchterm is:
$query = "select * from books where ? like ?";
...
$stmt->execute(array($searchtype, '\'%'.$searchterm.'%\''));
I got the same result.
Any help is appreciated. Thanks!
/ UPDATE ****/
I found on example 12 of http://us3.php.net/manual/en/pdo.prepared-statements.php
Example #12 Invalid use of placeholder
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));
// Below is What they suggest is the correct way.
// placeholder must be used in the place of the whole value
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?>
I tried this, and even though I no longer get a Warning, I do not get any results. However when I execute the query directly I will get a couple of results. Any thoughts?
Don't add the quotes when binding prepared variables and dont bind the column name
$query = sprintf( "select * from books where %s like ?", $searchtype );
...
$stmt->execute(array($searchtype, '%'.$searchterm.'%'));
$stmt->execute(array($searchtype, '\'%'.$searchterm.'%\''));
This isn't how parameterised queries work. Inserted parameters act as literal strings already, you don't have to add quote delimiters around them or escape them (that's the whole point), and if you try, you're literally comparing against the string single-quote-searchterm-single-quote.
Consequently if you are (as I suspect) intending to compare a particular column against a literal string, you don't parameterise the column name. At the moment you are comparing a literal string to another literal string, so it'll either always be true or always false regardless of the data in the row!
So I think what you probably mean is:
$query= "SELECT * FROM books WHERE $searchtype LIKE ?";
$like= "%$searchterm%";
$stmt->execute(array($like));
thought naturally you will have to be very careful that $searchtype is known-good to avoid SQL-injection. Typically you would compare it against a list of acceptable column names before using it.
(Aside: there is a way of putting arbitrary strings in a schema name that you can use for a column, but it's annoying, varies across databases and there isn't a standard escaping function for it. In MySQL, you backslash-escape the backquote character, quotes and backslashes and surround the name with backquotes. In ANSI SQL you use double-quotes with doubled-double-quotes inside. In SQL Server you use square brackets. However in reality you vary rarely need to do any of this because really you only ever want to allow a few predefined column names.)
(Another aside: if you want to be able to allow $searchterm values with literal percents, underlines or backslashes in—so users can search for “100%” without matching any string with 100 in—you have to use an explicit escape character, which is a bit tedious:)
$query= "SELECT * FROM books WHERE $searchtype LIKE ? ESCAPE '+'";
$like= str_replace(array('+', '%', '_'), array('++', '+%', '+_'), $searchterm);
$stmt->execute(array("%$like%"));
The problem I see is if you had written a wrapper for PDO, then you would have to somehow handle this separately. The answer I had found and loved was write your query and concat the % to the parameter. i.e. "WHERE column like concat('%', :something, '%')"

Categories