mysqli_stmt_bind_param variable type - php

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.

Related

When to use prepared statements in PHP Mysqli? - User form search input vs select queries

I am trying to understand when I should use prepared statements in php/mysqli. Should every php/mysqli query use prepared statements or just queries and instances where user input is involved ... such as an html form that asks a user to enter data to search within a database?
I am migrating my old php5/mysql code to php7/mysqli. I have many php files that query a mysql db. I would like clarification if I need to use prepared statements for every php file that connects to a mysql db ... for example php files that are referenced via "php require" and include simple sql select statements to render images and links to a html page?
<?php
//establish connection
$con = new mysqli('localhost','uid','pw','db');
//check connection
if ($con->connect_error) {
die("Connection failed: " . $con->connect_error);
}
//search variable that stores user input
$search = "%{$_POST['search']}%";
//prepare, bind and fetch
$stmt = $con->prepare("SELECT image, caption FROM `tblimages`
WHERE catid = 3 AND caption LIKE ? order by caption ASC");
$stmt->bind_param("s", $search);
$stmt->execute();
$stmt->bind_result($image,$caption);
while ($stmt->fetch()) {
echo "{$image} <br> {$caption} <br>";
}
$stmt->close();
//close database connection
mysqli_close($con);
?>
The code above works and is the first I've ever used prepared statements. It takes user input from a form (blank box to enter a search term - POST) and searches a db ... then renders results to an html page. This seems like a logical use of prepared statements. However ... I have other php files where users select data from a drop down box in a form to render a result (the user does not enter data into a search box like above). Do I use prepared statements for that instance as well? Plus do I use prepared statements for php files that are referenced via "php require" and include simple sql select statements to render images and links to a html page? I've yet to find clarification of the specific instances to use prepared statements to prevent sql injections. Any clarification or references welcome.
Short answer: Always use prepared statements.
Long answer:
Prepared statements separate your data from SQL commands. They are provided by PDO or by MySQLi. Their biggest advantage is that it is impossible to have SQL injection if your data is treated as data. Another advantage is that you can execute the same query over and over again with different set of data, which might be better for your performance and often keeps your code cleaner.
However, there are times when you would like to have some kind of dynamic query based on user's selection or actions. As you probably know table and column names are not data, but part of SQL query, therefore you can't keep them separated. The alternative to prepared statements then is to have a white list of possible values and only allow user input validated against the white list.
You might ask what are query, real_query, multi_query and PDO::exec good for?
As the PHP Manual shows they are good at times when you only need to execute constant query without any variables or when you have a query which can't be prepared. e.g.
$mysqli->query('SELECT Name FROM City LIMIT 10');
$pdo->exec('DELETE FROM fruit');
$mysqli->multi_query('DELETE FROM fruit; DELETE FROM pets;');
What if you know the type and values of your data? Should you also prepare/bind?
Yes! Get into a habit of binding all data going with SQL query. There is no reason to make exceptions. It is much more difficult to trace those exceptions in your code and always be sure you do not overwrite the "safe" value with some unknown input.
If you are still not sure how to use prepared statements or you think that they are too complicated (they are not) you can take a look at an amazing PHP tutorial at https://phpdelusions.net
This is how MySQLi prepared statements work in PHP:
Prepare an SQL query with empty values as placeholders (with a question mark for each value).
Bind variables to the placeholders by stating each variable, along with its type.
Execute query.
The four variable types allowed:
i - Integer
d - Double
s - String
b - Blob
A prepared statement, as its name implies, is a way of preparing the MySQL call, without storing the variables. You tell it that variables will go there eventually — just not yet. The best way to demonstrate it is by example.
$stmt = $mysqli->prepare("SELECT * FROM myTable WHERE name = ? AND age = ?");
$stmt->bind_param("si", $_POST['name'], $_POST['age']);
$stmt->execute();
//fetching result would go here, but will be covered later
$stmt->close();
If you've never seen prepared statements before, this may look a little weird.
Basically what's happening is that you are creating a template for what the SQL statement will be.
In this case, we are selecting everything from myTable, where name and age equal ?. The question mark is just a placeholder for where the values will go.
The bind_param() method is where you attach variables to the dummy values in the prepared template.
Notice how there are two letters in quotes before the variables.
This tells the database the variable types.
The s specifies that name will be a string value, while the i forces age to be an integer.
This is precisely why I didn't add quotation marks around the question mark for name, like I normally would for a string in an SQL call.
You probably thought I just forgot to, but the reality is that there is simply no need to (In fact, it actually won't work if you do put quotes around the ?, since it will be treated as a string literal, rather than a dummy placeholder.).
You are already telling it that it will be a string literal when you call bind_param(), so even if a malicious user tries to insert SQL into your user inputs, it will still be treated as a string.
$stmt->execute() then actually runs the code; the last line simply closes the prepared statement. We will cover fetching results in the Select section.

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).

specifying mysqli bind_param types

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.

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

What does bind_param accomplish?

I'm learning about avoiding SQL injections and I'm a bit confused.
When using bind_param, I don't understand the purpose. On the manual page, I found this example:
$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $code, $language, $official, $percent);
$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;
Now, assuming those 4 variables were user-inputted, I don't understand how this prevents SQL injections. By my understanding, they can still input whatever they want in there.
I also can't find an explanation for the 'sssd' in there. What does it do? Is that what makes it secure-er?
Final question: I read on another question that mysqli_real_escape_string is deprecated, but it doesn't say that in the manual. How is it deprecated? Can it not escape special characters anymore for some reason?
Note: This question explained what bind_param does, but I still don't understand why it is any safer or more protected.
Bind_param explanation
Now, assuming those 4 variables were user-inputted, I don't understand
how this prevents SQL injections. By my understanding, they can still
input whatever they want in there.
The main principle there is using prepared statement which is designed for sending safe query to db server, this can be done by escaping user input which is not part of the real query, and also checking the query without any (where clause) to check the validity of the query before using any parameters.
From this question: PDO sends raw query to MySQL while Mysqli sends prepared query, both produce the same result
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username =?")) {
$stmt->bind_param("i", $user);
$user = "''1''";
server logs:
130802 23:39:39 175 Connect ****#localhost on testdb
175 Prepare SELECT * FROM users WHERE username =?
175 Execute SELECT * FROM users WHERE username =0
175 Quit
By Using prepared statement, db server will check the query without any parameter, at this stage, errors can be detected before binding any parameter, then, if the query was valid, parameters also will be send to the server for finalizing the query.
From PHP Manual http://php.net/manual/en/mysqli.quickstart.prepared-statements.php:
Escaping and SQL injection
Bound variables will be escaped automatically by the server. The
server inserts their escaped values at the appropriate places into the
statement template before execution. A hint must be provided to the
server for the type of bound variable, to create an appropriate
conversion. See the mysqli_stmt_bind_param() function for more
information.
..
I also can't find an explanation for the 'sssd' in there. What does it
do? Is that what makes it secure-er?
The answer is here: http://php.net/manual/en/mysqli-stmt.bind-param.php
i
corresponding variable has type integer
d
corresponding variable has type double
s
corresponding variable has type string
b
corresponding variable is a blob and will be sent in packets
Final question: I read on another question that
mysqli_real_escape_string is deprecated, but it doesn't say that in
the manual. How is it deprecated? Can it not escape special characters
anymore for some reason?
Can you give a reference? I think you misunderstood with (mysql_real_escape_string())
By using prepared statements you are separating SQL queries from user entered data. Instead of input data, you put placeholders ('?' char) in your SQL query. Then you send the query to the DBMS server (e.g.: MySQL) by means of the "mysqli::prepare" method. So the server checks that everything is ok and, if so, it waits for input data. By now it already knows your query. Just it has to wait for input data to bind to the query.
At this point, "bind_param" comes into action, binding placeholders to user entered data.
Notice that bind_param only binds data to placeholders leaving unchanged the query.
So there is not way to change the original SQL query, because it has already sent to the server by means of the prepare method and because you are sending SQL queries and input data separately so user entered data can't interfere with queries.
ANYWAY...
The actual purpose to use a prepared statement in SQL is to cut the cost of processing queries, NOT to separate data from query. That's how it's being used now, not how it was designed to be used in the first place.
'sssd' stands for "string", "string", "string" and "double".
In fact: $code is a string, $language is a string, $official is a string and $percent is a double type.
mysqli_real_escape_string is not deprecated but mysql_real_escape_string is deprecated
(the first one is mysqlI, where I stands for "improved").

Categories