I'm beginning to use prepared statements with my sql queries in php and in starting with this I have come up with a question.
I have a function that grabs a user's id from a table at login. I want the user to be able to use either their username or email address for their login.
So my sql statement is:
SELECT * FROM `login` WHERE `username`=? OR `emailAddress`=?
Now essentially when in this query username and emailAddress will be the same because it can be either or.
So when binding my statements do I bind my variable twice:
bind_param('ss', $user, $user);
So the value for username and emailAddress needs to be the same. Essentially I want $user to be the value of both the placeholders.
My questions are: Am I doing this correctly? Is there a more efficient way?
Yes, you would have to bind it twice. If you are opposed to that for some reason, you could rephrase the query as:
SELECT *
FROM `login` l cross join
(select ? as thename) const
WHERE l.`username` = thename OR `emailAddress` = thename;
This is using a subquery to name the parameter so it can be referred to multiple times in the query.
Yes. There have to be as many variables in the bind_param() call as there are placeholders in the query. Consider if you had:
SELECT * FROM login
WHERE username = ? and emailAddress = ? and country = ?
and you tried to bind too few of them:
bind_param("ss", $user, $country);
How is it supposed to know which variable should be repeated for the extra placeholder?
There's no problem with using the same variable twice. I wouldn't recommend it with bind_result, though -- it will presumably allow it, but I don't know if it's predictable which column will be put into the variable.
Related
I am trying to refer to a column name to order a query in an application communicating with an Oracle database. I want to use a bind variable so that I can dynamically change what to order the query by.
The problem that I am having is that the database seems to be ignoring the order by column.
Does anyone know if there is a particular way to refer to a database column via a bind variable or if it is even possible?
e.g my query is
SELECT * FROM PERSON ORDER BY :1
(where :1 will be bound to PERSON.NAME)
The query is not returning results in alphabetical order, I am worried that the database is interpreting this as:-
SELECT * FROM PERSON ORDER BY 'PERSON.NAME'
which will obviously not work.
Any suggestions are much appreciated.
No. You cannot use bind variables for table or column names.
This information is needed to create the execution plan. Without knowing what you want to order by, it would be impossible to figure out what index to use, for example.
Instead of bind variables, you have to directly interpolate the column name into the SQL statement when your program creates it. Assuming that you take precautions against SQL injection, there is no downside to that.
Update: If you really wanted to jump through hoops, you could probably do something like
order by decode(?, 'colA', colA, 'colB', colB)
but that is just silly. And slow. Don't.
As you are using JDBC. You can rewrite your code, to something without bind variables. This way you can also dynamically change the order-by e.g.:
String query = "SELECT * FROM PERS ";
if (condition1){
query = query+ " order by name ";
// insert more if/else or case statements
} else {
query = query+ " order by other_column ";
}
Statement select = conn.createStatement();
ResultSet result = select.executeQuery(query);
Or even:
String columnName = getColumnName(input);
Statement select = conn.createStatement();
ResultSet result = select.executeQuery("SELECT * FROM PERS ORDER BY "+columnName);
ResultSet result = select.executeQuery(
"SELECT * FROM PERS ORDER BY " + columnName
);
will always be a new statement to the database.
That means it is, like Thilo already explained, impossible to "reorder" an already bound, calculated, prepared, parsed statement. When using this result set over and over in your application and the only thing, which changes over time is the order of the presentation, try to order the set in your client code.
Otherwise, dynamic SQL is fine, but comes with a huge footprint.
This question already has answers here:
Are PDO prepared statements sufficient to prevent SQL injection?
(7 answers)
Closed 7 years ago.
I'm thinking of an example like this one:
The request hits a page at an url (by whichever means), with a parameter. example.com/api/page?name=bob. It's my understanding that you should do a prepared statement to get the $_POST[name]parameter and make sure it's not anything funky, but it does so by evaluating the expression.
My first question is: How does it do so (evaluate the expression)?
My second question is:
What if a user inputs something along the lines of "SELECT * FROM users" or "DROP TABLE users" that gets passed to the $_POST['name'] parameter (the ?name=bob at the end), what would happen in that case?
Just as an example, the final query would be something like
SELECT name, continent FROM world
WHERE continent IN
(SELECT continent FROM world WHERE name='Brazil')
the second select acting as the user input parameter - so $_POST['name'] contains this query SELECT continent FROM world WHERE name='Brazil'
Lastly, the third question i have is how can i protect against something like that?
I'm guessing PDO is design specifically to prevent query within query(?), but after reading around a bit i'm still quite confused.
I'm still learning all of this so if i'm not clear or specific enough in my inquiry please let me know, and i'll try and address that.
EDIT:
To clear any confusion, what i'm doing is this:
$pdo = new PDO('..');
$sql = 'SELECT id FROM users WHERE username = :username';
$statement = $pdo->prepare($sql);
$statement->bindParam(':username', $_POST['username']);
Question is, what if $_POST['username'] contains 'SELECT * FROM users' (or any other query) ?
How does prepare() work? Can what i described actually present a security hole? I need some help in understanding this.
To clear any confusion, what i'm doing is this:
$pdo = new PDO('..');
$sql = 'SELECT id FROM users WHERE username = :username';
$statement = $pdo->prepare($sql);
$statement->bindParam(':username', $_POST['username']);
Question is, what if $_POST['username'] contains 'SELECT * FROM users' (or any other query) ?
This query would return the ids of all users with the username "SELECT * FROM users".
By passing $_POST['username'] as parameter the database knows that whatever string $_POST['username'] may contain it is NOT part of the query. It's just a string.
This prevents SQL injection since the parameter will NOT be executed. This also means that
SELECT name, continent FROM world
WHERE continent IN
(SELECT continent FROM world WHERE name='Brazil')
the second select acting as the user input parameter - so $_POST['name'] contains this query SELECT continent FROM world WHERE name='Brazil'
won't work. Because you can't include queries in parameters. Well you can but they will not be executed.
I'm learning mysqli prepared statements and have a few questions about it
From what I have understood we use prepared statement for those queries that have dynamic variable in them for eg in login - email & password.
I want to know if prepared statements are necessary for queries where no dynamic element is there for eg fetching users from database. If I do this like below query does this makes it vulnerable
SELECT
name, email
FROM
users
How can I use prepared statement without using bind param?
Like in pdo we do like this
$array=array($email,$pass);
$db->query("SELECT name from users where email=? and password=?");
$db->execute($array);
Can I do something like this in mysqli? I have searched and found results that use bind param , nothing without using bind.?
Your answers are as follows:
1.See this-stackoverflow.com/questions/5108414/mysqli-query-vs-prepare-(the link that AdRock posted in his comment.)
2.Instead of-
$db->query("SELECT name from users where email=? and password=?");
$db->bind_param("ss", $email, $password);
$db->execute($array);
You can do this-
$db->query("SELECT name from users where email='$email' and password='$password'");
$db->execute($array);
I can see many discussions on why is better to use PDO bindValue vs bindValue. But what I could not find was precice information on why should I use that vs a simple variable in the query. Could anyone tell me? thanks
$sex = 'male';
$s = $dbh->prepare('SELECT name FROM students WHERE sex = :sex');
$s->bindParam(':sex', $sex);
$s->execute();
VS
$sex = 'male';
$s = $dbh->query('SELECT name FROM students WHERE sex = $sex'); // OR PREPARE, The question is how to pass the variable.
Like others have said, you want to use PDO to prevent SQL injection. Say a user with bad intentions types something like ';drop table students;-- into an input box on your site. Without PDO, the final query will look like this:
SELECT name FROM students WHERE sex = '';drop table students;--'
See what would happen? The select statement would run and not find any results (unless you have students in your table with no sex specified). Then, the drop statement would run, and your entire students table would be deleted.
This is just one example—there are all kinds of SQL injection attacks, many of them more dangerous than this. Using PDO prevents pretty much all of them. Internally, the bound variables are kept separate from the query itself.
The main reason is by using prepared statements and bound variables you protect yourself against the most common vector used for sql injection attacks.
A second reason is if you have multipe requests to run the same query statement, but with different variable values, you can save time by only having the server calculate the execute plan once, then run it on the the variables as you call the same statement over and over. Think about looping over the same statement several time. This is the concept of serverside prepared statements which mysql allows and PDO supports.
I've exhausted all efforts at what appears to be a trivial problem, but gotten nowhere.
There is a simple Prepare statement:
$qry = $core->db->prepare("SELECT * FROM users WHERE email = '?'");
$qry->execute(array('email#address.com'));
However, no rows are returned. Running the query with the parameters hardcoded into the query results in a successful selection of one row. I've tryed many different methods of doing the prepare, but even it this most simple form it isn't working.
The PDO object is stored in a singleton called Core. PDO is using the mysql driver.
Remove quotes from the query:
("SELECT * FROM users WHERE email = ?");
The reason to use placeholders (? symbol) is to forget about quotes. PDO will add them automatically.