PHP PDO::bindParam() data types.. how does it work?
In other DB abstraction frameworks in other languages it can be used for things like making sure you're doing the proper escaping for in-lining values (for drivers that don't support proper bound parameters) and improving network efficiency by making sure numbers are binary packed appropriately (given protocol support). It looks like in PDO, it doesn't do much.
if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && ! ZVAL_IS_NULL(param->parameter)) {
if (Z_TYPE_P(param->parameter) == IS_DOUBLE) {
char *p;
int len = spprintf(&p, 0, "%F", Z_DVAL_P(param->parameter));
ZVAL_STRINGL(param->parameter, p, len, 0);
} else {
convert_to_string(param->parameter);
}
} else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && Z_TYPE_P(param->parameter) == IS_BOOL) {
convert_to_long(param->parameter);
} else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(param->parameter) == IS_LONG) {
convert_to_boolean(param->parameter);
}
So, if you say it is a STR (or if you say nothing at all as that is the default) and your data's internal type is a double then it will turn it into a string using one method, if it's not a double then it will convert it to a string using a different method.
If you say it's an int but it is really a bool then it will convert it to a long.
If you say it's a bool but it's really a number then it will convert it to a true boolean.
This is really all I saw (quickly) looking at the stmt source, I imagine once you pass the parameters into the driver they can do additional magic. So, I'd guess that all you get is a little bit of do the right and a whole lot of behavior ambiguity and variance between drivers.
bindParam works correctly no matter what data type is specified or given
PDO::PARAM_INT
and PDO::PARAM_STR
when passed to bindParam()
are indications that the driver is free to ignore.
Looking at PDO pg driver's source code, it appears that, except for PDO_PARAM_LOB
which is treated specially, all types are quoted as strings (that is, between quotes and passed to libpq's PQescapeStringConn
function)
You should also be aware of the PDO::ATTR_EMULATE_PREPARES
attribute that controls what method is used under the hood. When false
, PQprepare()
is used with real out-of-query parameters. If true
, parameter values are injected into the SQL passed to the non-parametrized PQexec()
.
Technically, this is quite different, so you may see differing behaviors in corner cases or error cases depending on this attribute.
Why do we need to specify the parameter type in bindParam()?
Using bindParam()
with types could be considered safer, because it allows for stricter verification, further preventing SQL injections. However, I wouldn't say there is a real security risk involved if you don't do it like that, as it is more the fact that you do a prepared statement that protects from SQL injections than type verification. A simpler way to achieve this is by simply passing an array to the execute()
function instead of using bindParam()
, like this:
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour');
$sth->execute(array(
'calories' => $calories,
'colour' => $colour
));
You're not obligated to use a dictionary, you can also do it just like you did with questionmarks and then put it in the same order in the array. However, even if this works perfectly, I'd recommend making a habit of using the first one, since this method is a mess once you reach a certain number of parameters. For the sake of being complete, here's what it looks like:
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < ? AND colour = ?');
$sth->execute(array($calories, $colour));
PDO::PARAM_INT is important in bindParam?
Yes, use it.
I did a few tests (with PDO::ATTR_EMULATE_PREPARES false
) and I found out that the quotes around the values will be different.
When you bind an integer value with PARAM_INT
there will be no quotes in the query (A string value with PARAM_INT has quotes). If you bind an integer value with PDO::PARAM_STR
there will be quotes and mysql has to cast to integer.
Examples:
$stmt->bindParam(':ThreadId', $threadid, PDO::PARAM_INT);
$threadid = 123;
// SELECT TagId FROM tagthread WHERE ThreadId = 123
$threadid = '123test';
// SELECT TagId FROM tagthread WHERE ThreadId = '123test'
// mysql will cast 123test to 123
EDIT:
I further tested and read on that topic. Conclusion: Implicit casting is dangerous and can lead to unexpected results.
Read more on that here. Another disadvantage to always use PDO::PARAM_STR
is the performance. Read more on performance Disadvantages of quoting integers in a Mysql query?
So if your column is of type [TINY|SMALL|MEDIUM|BIG]INT
than use PARAM_INT
. And in case it is a LIMIT
clause than cast to integer if the variable type in PHP is not integer.
PHP pdo bindParam type management
You've got several mistakes in your code.
However, let's go over what the types PDO::PARAM_INT
, PDO::PARAM_STR
and PDO::PARAM_NULL
are telling MySQL to do.
Those values are telling PDO how to treat the input, not to disallow input. If you send text, but the column is int
then MySQL will attempt to coerce the data into int
. It won't tell you "you entered abcd but expected value was integer". You must do this check on your own before passing data to PDO
.
Now onto other problems:
Don't use
bindParam
.bindParam
accepts the value by reference. This is intended for when you invoke stored procedures and variable is supposed to be modified based on procedure's output. UsebindValue
. If you tried to do the following withbindParam
, it wouldn't work and you'd get an error:$stmt->bindParam(':my_column', 1, PDO::PARAM_INT); // It fails and yields an error
Don't lock tables. You're already using transactions, no need to lock the table, MySQL handles concurrency and access for you.
Bottom line - perform validation before using PDO
for inserting. PDO
helps you clean the input based on connection information (among other things). It won't perform validation.
PDO bindParam variable datatype from array
Just change your array definition to use the PDO constants like this:
$imp->datafields=array(
"id" => PDO::PARAM_INT,
"name" => PDO::PARAM_STR,
"cookieLength" => PDO::PARAM_INT
);
And then in your foreach loop just use $value
alone like this:
$stmt->bindParam(":$key", $program->$key, $value);
//^ ^ ^^^^^^
And also use double quotes that the variables gets parsed in it!
What you could also do if you really want it just to use constant()
in every iteration like this:
$stmt->bindParam(":$key", $program->$key, constant("PDO::$value"));
Does PDO::bindParam / bindValue throw an exception if the data type is different from the supplied?
At least for mysql - no, it will never throw an error.
Moreover, 99.99% of time mysql is happy with PDO::PARAM_STR for any type. Therefore, you can simplify your insert function dramatically, omitting all the unnecessary stuff from the $values array:
public function insert($sql, $values){
return $this->connect()->prepare($sql)->execute($values);
}
$array = array('jotName' => 'some jot string');
$db->insert($sql, $array);
List of PDOStatement::bindParam data_type parameters
From the documentation here:
PDO::PARAM_BOOL (integer)
Represents a boolean data type.
PDO::PARAM_NULL (integer)
Represents the SQL NULL data type.
PDO::PARAM_INT (integer)
Represents the SQL INTEGER data type.
PDO::PARAM_STR (integer)
Represents the SQL CHAR, VARCHAR, or other string data type.
PDO::PARAM_LOB (integer)
Represents the SQL large object data type.
PDO::PARAM_STMT (integer)
Represents a recordset type. Not currently supported by any drivers.
PDO::PARAM_INPUT_OUTPUT (integer)
Specifies that the parameter is an INOUT parameter for a stored procedure. You must bitwise-OR this value with an explicit PDO::PARAM_* data type.
How define the variable type in PDOStatement::bindValue()?
I'm no PDO-expert, but I can think of a few scenarioes where the data_type parameter is both useful and even needed.
Output parameters
When you define output or input/output parameters, you must provide both type and length of the expected output parameter.
Ref: http://www.php.net/manual/en/pdo.prepared-statements.php
Example #4
$stmt = $dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
Example #5
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
DBMs without implicit casting
Explained in another answer to this question...
When parameter is not bound to castable data
Even databases with casting abilities will not always be able to cast you variable correctly.
Ref: Reasons to strongly type parameters in PDO?
$limit = 1;
$dbh->prepare("SELECT * FROM items LIMIT :limit");
$dbh->bindParam(":limit", $limit, PDO::PARAM_STR);
// Will throw "You have an error in your SQL syntax..."
Related Topics
How to Get the Unicode Value of a Character or Vise Versa with PHP
How to Get Previous Month and Year Relative to Today, Using Strtotime and Date
How to Make PHP Generate Chunked Response
Why Does Tcpdf Ignore My Inline CSS
How to Call the Constructor with Call_User_Func_Array in PHP
Php/Regex: How to Get the String Value of HTML Tag
Any Way to Specify Optional Parameter Values in PHP
Rerouting All PHP Requests Through Index.Php
How to Include Authorization Header in Curl Post Http Request in PHP
Exotic Names for Methods, Constants, Variables and Fields - Bug or Feature
How to Detect Country/Location of Visitor
Do SQL Connections Opened with Pdo in PHP Have to Be Closed
Replace String in Text File Using PHP
Call to Undefined Function Apache_Request_Headers()
How to Fetch Associative Array Grouped by the Values of a Specified Column with Pdo
Is My Understanding of PHP Sessions Correct
PHP Inserting Multiple Checkbox and Textbox Arrays into MySQL Database