specifying mysqli bind_param types - php

what are the pros and cons of specifying mysqli bind_param types i,d,s,b?
I store a UNIX timestamp in a db column with data type INT. In my prepared statement I set it to bind_param('s',$timestamp); and it stores the value without any problems. So what impact did it make that I used s instead of i during bind_param?

It influences how MySQL will see the query/value. Take this query:
INSERT INTO foo VALUES (?)
If you bind the parameter as int:
$stmt->bind_param('i', $bar);
Then the query will be about equivalent to:
INSERT INTO foo VALUES (42)
However, if you bind as string:
$stmt->bind_param('s', $bar);
The query will be about equivalent to:
INSERT INTO foo VALUES ('42')
In many cases MySQL doesn't particularly care whether you send it a string or an int and will simply cast the value to the appropriate type on the fly, just as PHP does most of the time. However, in some circumstances and with some types you may get an unexpected conversion, which is why you should bind the value as the type that you want it as and not leave it up to MySQL's casting rules.

Related

Do I need to use prepared statement for the data I'm getting from database?

I have a query like this:
$result = $db
-> prepare("SELECT value FROM mytable WHERE id = ?")
-> execute(array($id))
-> fetch(PDO::FETCH_ASSOC);
And I want to use $result['value'] as a parameter for another query (an UPDATE statement). Should I use prepared statement for that UPDATE statement? Or because I've taken it from database, then no need to pass it as prepared statement?
Yes. Use a prepared statement with a bind placeholder.
Just because a value is being returned from a database doesn't mean that the value is safe for inclusion in SQL text.
You may have domain knowledge that the value column in mytable is INTEGER type, so that it would be safe. But in the more general case, and for the reader who doesn't know the definition of mytable, and what value might contain. A reader of your code is going to assume that value isn't "safe". For all we know, we could be getting something like this:
Robert'); DROP TABLE students; --
Whenever we see a variable concatenated into the SQL text, we are going to assume that the variable could contain something other than a value, and it could contain actual SQL. (Or, if we do see a variable concatenated into the text of a SQL statement, we would be expecting that it's going to be properly escaped right at the point it's being concatenated.)
So, the preferred pattern would be use a prepared statement with a bind placeholder. That makes it unambiguous to the reader that value is indeed a value, and that it's not intended to be interpreted as SQL text.

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

Binding values and Parameters in PDO Prepared Statements :PHP

As PDOStatement::execute documentation says, "All values are treated as PDO::PARAM_STR.
So I have following questions
1)Suppose I have a variable $_SESSION['id']=2 and a query
$sql='select * from articles where id=?';
$query=$con->prepare($sql);
$query->execute(array($_SESSION['id']));
When I execute the statements,it executes successfully.
It signifies that it passes variable as an integer .Does it do automatic casting or it violates the documentation statement?
2)Suppse I have another query
select * from articles where id=? and category=?
Now here first parameter is int and last parameter is string so when I bind parameters $query->bindValue(2, $_GET['category'],PDO::PARAM_STR); do I need to specify PDO::PARAM_STR or I can rely on the default implementation that it is considered as string by default as the documentation says.
3)I want to specify table name from $_GET['category'] into the query but I get the following format of the string(notice the quotes around table name) and hence SQL error.How can I correct it?
select * from 'article'...........
1) When I execute the statements,it executes successfully. It
signifies that it passes variable as an integer .Does it do automatic
casting or it violates the documentation statement?
No, it does pass the parameter as string. MySQL is casting it back to an int transparently because the column is an int value, which in this case has no side effects.
2) do I need to specify PDO::PARAM_STR or I can rely on the default
implementation that it is considered as string by default as the
documentation says.
Unless the API ever changes, it's pretty sure that it's bound as a string if the documentation says so. I doubt the API will change that any time soon, or at all. I might still explicitly bind it as string, just to make it extremely clear to a reader of the source code.
3) I want to specify table name from $_GET['category'] into the query
...
You cannot. You can only "placehold" values, not identifiers or other structural elements of the query. Parameterised statements are explicitly to separate between the structure of the query and the values dynamically interpolated into it; if you could dynamically interpolate structural elements there'd be no point to this separation.

mysqli_stmt_bind_param variable type

I'm converting from mysql_ to mysqli_ and still new to mysqli_. Here is my code:
$stmt = mysqli_prepare($con, "INSERT INTO test VALUES (?, ?)");
mysqli_stmt_bind_param($stmt, 'ss', $a, $b);
$a=1;
$b=1.5;
mysqli_stmt_execute($stmt);
My question is:
$a has Integer value
$b float
but the corresponding variable type in mysqli_stmt_bind_param ss (string,string).
the result is data succesfuly inserted to table, is work as intended or i'm doing wrong?
Actually bind functions (mysqli_stmt_bind_param or PDOStatement::bindParam) are not validation functions. You show how to interpret your value only and what type of value you want to get from result.
Answer is: it is work as intended.
Are the fields in the table that this statement targets set up as integer/floats? Or are they set up as strings in the database (some people do this, for whatever reason). Also, as for prepared statements being slower, I believe that is only the case when running a run once unique query. If you are making several queries in a loop, prepared statements are, I believe, significantly faster (provided the statement was constructed outside of the loop).
The source variable can be of any type really, but it will attempt to convert to string when preparing the query because thats the type you said the query takes.
What really matters are the types of the fields in the table. I'm not sure how PHP handles this but if the query takes an integer (i) and you try to prepare it as a string (s) it may cause an error. In any case you should specify the correct type to avoid problems.

Categories