Differences between using ? and :param in prepare statement - php

Let's say I want to select records where Id = 30. Prepared statements allow two ways of binding parameters:
question marks
$id = 30;
$q = $conn->prepare("SELECT * FROM pdo_db WHERE id > ?");
$q->execute(array($id)); // Here above ID will be passed
named parameters
$sth = $conn->prepare("SELECT `id`, `title` FROM `pdo_db` WHERE `id` > :id");
$sth->execute(array(
':id' => 30
));
Both are working fine and give accurate results but I am not able to get the exact differences between these two nor when I should use one or another?

Question mark parameters are called positional parameters.
Parameters defined with : and a name are called named parameters.
The rule is that you can't mix the two in your prepared statement.
Positional parameters work in a simple way - if you have two positional parameters, you can specify an array with two elements. Array values will be bound in order as they appear in the array.
Named parameters are a bit trickier, they don't have to be bound in order they appear. You can also repeat one named parameter multiple times in the statement, but you can bind it only once to pass the value - that last part works when PDO is set to emulation via $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, TRUE);.

This seesm to be more of a preference based question as there isn't a strict right or wrong answer.
Personally I avoid ? as it's tightly tied to the order of parameters. Although theoretically you shouldn't be able to mess this up by adding or removing binding a single binding, it just seems like it's asking for trouble. It is (slightly) less work though.
:name is more concise and is tightly bound to the identification of bindings, not arbitrarily to the order. It involves a (tiny) bit more work but it is much easier to debug, and less prone to mistakes.
I prefer being (slightly) concise over writing (slightly) less code.

These are different placeholders
? -- > question mark placeholders
:name --> named Placeholders
The difference between named and question mark placeholders is that with question mark placeholders you'll have to take care about the order in which they will be bound to the query.

Related

Should you use prepared statments on LIMIT

One day I was googling to understand when a prepared statment should be used. As I searched online many claimed that you should use always prepared statments. Now the question I have is... does this also count for LIMIT? I mean it is possible (I tried) but is it really that rational? Same question on ORDER BY too.
When the database does not allow you to use a parameter on a specific location of the SQL statement you need to assemble the query on the fly, by the use of Dynamic SQL. That is... concatenating strings to get a full functioning SQL query.
Now, the trick is to make it safe against SQL Injection. To do this:
Make sure the value for LIMIT is an integer, and not something unsafe coming right from the UI like 3; DROP TABLE EMPLOYEE.
For the ORDER BY clause make sure the columns are not coming from the UI "as is"; use some kind of projection. For example, if there are 50 columns to order by, the UI can display them all, but then just send a number (from 1 to 50) to the backend; the backend receives this number and reconstitutes the ordering column(s) from it.
Normally the LIMIT parameters must be literals, not values that can be substituted for placeholders, so you would have to validate that they're integers before substituting into the string.
However, if you use PDO rather than mysqli, it allows you to perform parameter substitution in the LIMIT clause, by using the PDO::ATTR_EMULATE_PREPARES option. This is automatically enabled for a specific prepared statement if it contains parameters in this clause. See How to apply bindValue method in LIMIT clause? for the specific details.

Reuse prepared statement with optional condition

I am using one pretty complex prepared statement with various conditions in the WHERE clause and at one point I actually need the same statement with one more specific condition. Creating two different statements is a bad approach since both share most of their query string and when I update one I would have to update the other one as well. So far I tried using this:
SELECT columns
FROM tables
WHERE manyConditions AND (specificColumn = ? OR ? = NULL)
In this scenario I could bind one arbitrary argument and NULL to render the specific condition useless for queries which don't need it ($pdo->execute([/* ... */, -1, null])) while still being able to filter by specificColumn when binding a proper value and something that is not NULL ($pdo->execute([/* ... */, 'specific value', true])).
This is a really dirty way to prevent code duplication which forces me to bind two more variables in most cases.
Is there a more elegant approach to prevent code duplication?
That's a very good question from a thoughtful programmer.
I'd say there is no equally elegant and simple solution. But I can offer a couple of approaches and you can decide which one is best for you.
You can use named placeholders and keep emulation mode turned on. In this case you will have to bind every variable only once. However, overall writing will remain the same as for named placeholders you have to repeat each name three times wither way.
As it was suggested in the now deleted answer, you could use conditional query building, something like
$sql = "SELECT columns FROM tables WHERE manyConditions";
$params = [$a,$b,$c];
if (!empty($d)) {
$sql .= " AND specificColumn = ?";
$params[] = $d;
}
$stmt = $pdo->prepare($sql);
$stmt->execute($params)

Can you omit PDO prepare if there's no placeholder/dynamic data in a query?

I'm working on an application at the moment that uses PDO with a MySQL database.
I'm seeing some queries, which are just very simple SELECT statements, e.g.
SELECT * FROM table ORDER BY name ASC
The code does not use prepare, for example:
$sql = "SELECT * FROM " . $this->table . " ORDER BY name ASC";
$stmt = $this->db->query($sql);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $results;
Is it ok to do this, i.e. without using prepare, if there's no placeholders in the query?
The reason I've asked this is because according to the documentation it says
The SQL statement can contain zero or more named (:name) or question mark (?) parameter markers
which makes me wonder why you'd use this in the case of having no (zero) parameter markers?
Yes, because the use of prepared statements have 2 main causes:
Enhance running the same query with different parameters.
Prevent sql injection by separating sql code from the parameters.
Since you have no parameters that could be handled by a prepared statement (table names cannot be a parameter), you do not gain anything by pushing the query through as a prepared statement.
You still need to make sure that whatever is returned by $this->table will not cause any issues with the generated sql code.
Of course you can omit prepare if there is no dynamic data in your query.
But prepared statements have more advantages than only securing your queries.
According to http://php.net/manual/en/pdo.prepared-statements.php a second advantage is, that statements can be prepared once and executed multiple times.
The query only needs to be parsed (or prepared) once, but can be executed multiple times with the same or different parameters. When the query is prepared, the database will analyze, compile and optimize its plan for executing the query. For complex queries this process can take up enough time that it will noticeably slow down an application if there is a need to repeat the same query many times with different parameters. By using a prepared statement the application avoids repeating the analyze/compile/optimize cycle. This means that prepared statements use fewer resources and thus run faster.
Nevertheless, if you run your query only once and there is no dynamic data inside your query, omitting prepare is also fine.
In reality, you have to run such a query extremely seldom. A few tables with configuration-like options may be.
In all other cases at least LIMIT clause is obligatory.
So the question is rather a theoretical one.

Is there any difference between using PDO::bindValue (with or without a type identifier) vs execute?

I have been using PDO for at least two years now, and I've noticed that all three of these methods are available to bind a value to a query.
Is there any difference, downfall, or reason against doing any of these three. Are they all correct and can be used freely without a consequence?
Using BindValue with a type identifier
$query = $pdo->prepare("INSERT INTO `cake` (`name`) VALUES(:name)");
$query->bindValue(":name", $cakeName, PDO::PARAM_STR);
$query->execute();
Using BindValue without a type identifier
$query = $pdo->prepare("INSERT INTO `cake` (`name`) VALUES(:name)");
$query->bindValue(":name", $cakeName);
$query->execute();
Binding the value using an array in an execute value
$query = $pdo->prepare("INSERT INTO `cake` (`name`) VALUES(:name)");
$query->execute([":name"=>$cakeName]); // shorthand array from PHP 5.4
I know this question has been asked before, though I haven't seen which one should be used and how it'll be handled. I also haven't seen one explaining the consequences of not using a type identifier, which is why I feel it's okay to post this. Is not setting it going to use more resources so it can try to judge by itself, is it bad practice not to set it? Just curious.
The only difference is that bindValue allows you to pass a third parameter: the type. With execute all values are bound as strings. With bindValue, you can bind values as integers, bools, blobs or other types. Sometimes this is absolutely necessary, e.g. for blobs. In other cases it doesn't make much of a difference, e.g. MySQL will handle WHERE foo = '42' (bound as string) the same as WHERE foo = 42 (bound as int).

Should we always bind our SQL statements?

I have been researching into PDO's bindValue(). I know that preparing my SQL statements with PDO is keeping SQL injections from happening.
Code Example:
$stmt = $dbh->prepare('SELECT * FROM articles WHERE id = :id AND title = :title');
$stmt->bindValue(':id', PDO::PARAM_INT);
$stmt->bindValue(':title', PDO::PARAM_STR);
$stmt->execute();
By binding the ID as a number, and the Title was a string, we can limit the damage done when someone tries to do an SQL injection within the code.
Should we always bind our values with a PDO::PARAM_ so we can limit what can be pulled from the database in an SQL injection? Does this add more security with PDO when doing our bindValue()?
There are two questions in one. It is essential not to confuse them
Should we always use a placeholder to represent a variable data in the query?
Should we always use certain function in the application code to follow the above rule?
Also, from the clarification in the comments under the opening post, the third question can be seen:
Should we always use third parameter, or it's OK to let PDO bind all the parameters as strings by default?
1. For the first question the answer is absolutely and definitely - YES.
While for the second one, for sake of code sanity and DRYness -
2. Avoid manual binding when possible.
There are many ways to avoid manual binding. Some of them are:
ORM is an excellent solution for the simple CRUD operations and must have in a modern app. It will hide SQL from you completely, doing the binding behind the scenes:
$user = User::model()->findByPk($id);
Query Builder is also the way to go, disguising SQL in some PHP operators but again hiding the binding behind the scenes:
$user = $db->select('*')->from('users')->where('id = ?', $id)->fetch();
some abstraction library may take care of the passed data by means of type-hinted-placeholders, hiding the actual binding again:
$user = $db->getRow("SELECT * FROM users WHERE id =?i", $id);
if you are still using PHP in the last century ways, and have raw PDO all over the code - then you can pass your variables in execute(), still saving yourself a lot of typing:
$stmt = $dbh->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
$user = $stmt->fetch();
As of the third question - as long as you are binding numbers as strings (but not the opposite!) -
3. It's all right with mysql, to send almost every parameter as a string
as mysql will always convert your data to the proper type. The only case known to me, is a LIMIT clause where you cannot format number as a string - thus, the only related case is one when PDO is set in emulation mode and you have to pass a parameter in LIMIT clause. In all other cases you can omit third parameter, as well as explicit call to bindValue() without any problem.
You should definitely use the prepare API and pass values separately from the query, as opposed to doing plain string interpolation (e.g. "SELECT * FROM foo WHERE bar = '$baz'" → bad).
For binding parameters, you have three options:
bindParam
bindValue
execute
It doesn't really matter which of these you use, they're all equally secure. See these answers for some details about the differences:
Confusion between bindValue() and bindParam()?
Using PDO without binding
When using bindParam or bindValue, passing the third PDO::PARAM_ argument type is optional. If you don't pass it, it defaults to binding the argument as string. That means you may end up with a query equivalent to ... WHERE foo = '42' instead of ... WHERE foo = 42. It depends on your database how it will handle this. MySQL will cast the string to a number automatically as needed, just as PHP does (e.g. in '42' + 1). Other databases may be more fussy about types.
Again, all options are equally safe. If you're trying to bind a string 'foo' using PDO::PARAM_INT, the string will be cast to an integer and accordingly bound as the value 0. There's no possibility for injection.
Yes you should always bind params with prepared statement.
It's more secure, and limit SQL injection. But this is not the only think you must do to query params: a correct type control is required, best if you map a row into an object and throw an exception in it if it has invalid data.
I hope I can be useful!
Yes, binding is the way to go. Or parameterised queries which a more generalized term.
#Theo does a wonderful job explaining why parameterized queries is the way to go
You could also use stored procedures for additional security but is an over kill if you have one application to one database. Its good for multiple applications to one database to ensure consistency when handling data

Categories