I have a text data type in a database that would like to enter true or false values. If I do using Mysqli or PDO with BindParam works correctly it adds 1 or 0 but when I try to use BindValue it only works true. False value is exchanged for an empty space.
try{
$conn = new PDO("mysql:host=localhost;dbname=name_db", "root", "");
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "INSERT INTO upload_meta (video_id, upload_key, upload_value) VALUES (:video_id,:upload_key,:upload_value)";
$temp = $conn->prepare($sql);
$temp->bindValue(':video_id', 11111111);
$temp->bindValue(':upload_key', 'exodo');
$temp->bindValue(':upload_value', false);
$temp->execute();
}catch(PDOException $e){
echo $e->getMessage();
}
This field will receive values of various types needing to be text.
CREATE TABLE `upload_meta` (
`meta_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`video_id` int(11) unsigned NOT NULL,
`upload_key` varchar(255) DEFAULT NULL,
`upload_value` varchar(255) DEFAULT NULL,
PRIMARY KEY (`meta_id`),
KEY `video_id` (`video_id`),
KEY `index_upload_key` (`upload_key`(191)),
CONSTRAINT `upload_meta_ibfk_1` FOREIGN KEY (`video_id`) REFERENCES `video` (`id_video`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
According to the documentation
The answer is in the documentation for bindParam:
Unlike PDOStatement::bindValue(), the variable is bound as a reference and will only be evaluated at the time that PDOStatement::execute() is called.
And execute
call PDOStatement::bindParam() to bind PHP variables to the parameter markers: bound variables pass their value as input and receive the output value, if any, of their associated parameter markers
Your case
Your database structure expects upload_value as varchar which is basically text/string. When you use bindParam it is working because it is passing the value of true or false i.e., 1 or 0
But when you use bindValue the reference is passed and then evaluated at the time of execution, and hence true is getting converted into 1 (string/text), but false is evaluated to "empty" string.
Solution
Either use bindParam or if you want to use bindValue you should update your database structure to accept boolean values for upload_value instead of varchar
A 5 min guide: https://w3guy.com/php-pdostatement-bindparam-bindvalue/
Related
This question already has answers here:
PHP PDO bindParam() and MySQL BIT
(2 answers)
Closed 3 years ago.
I am trying to update my table using the following:
$stmt = $db->prepare("
UPDATE Business SET
Business.Name = ?,
Business.Phone = ?,
Business.Fax = ?,
Business.Address = ?,
Business.City = ?,
Business.StateId = ?,
Business.Zip = ?,
Business.Referral = ?,
Business.IsRemindedWeekly = ?,
Business.DeletedOn = ?
WHERE
Business.BusinessId = ?");
// Execute the query
$stmt->execute(array(
$_POST["Name"],
$_POST["Phone"],
$_POST["Fax"],
$_POST["Address"],
$_POST["City"],
$_POST["StateId"],
$_POST["Zip"],
$_POST["Referral"],
$_POST["IsRemindedWeekly"],
($_POST["DeletedOn"] && $_POST["DeletedOn"] != "0000-00-00" ? $_POST["DeletedOn"] : null),
$_POST["BusinessId"]
));
And my schema looks like this:
CREATE TABLE `business` (
`BusinessId` int(11) NOT NULL,
`Name` varchar(255) NOT NULL,
`Phone` char(10) DEFAULT NULL,
`Fax` char(10) DEFAULT NULL,
`Address` varchar(255) DEFAULT NULL,
`City` varchar(64) DEFAULT NULL,
`StateId` int(11) DEFAULT NULL,
`Zip` char(5) DEFAULT NULL,
`Signature` blob DEFAULT NULL,
`Referral` varchar(255) DEFAULT NULL,
`IsRemindedWeekly` bit(1) NOT NULL DEFAULT b'0',
`DeletedOn` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
However, the IsRemindedWeekly column is always being set to 1 regardless of the value sent to the request. When inspecting the network tab the payload appears to be sending a String value of "1", but even if I change my parameterized value to:
($_POST["IsRemindedWeekly"] == "1" ? 1 : 0)
(notice the non-type comparison operator) but regardless, the value in my database is still 1 after update operation. Am I missing something?
UPDATE
I am a little upset that the thread was closed because I'm still having difficulties. I've decided to use bindValue but it still isn't working. I've tried:
// Passing a 1 or 0 with PARAM_INT always returns false
$stmt->bindValue(":isRemindedWeekly", ($_POST["IsRemindedWeekly"] == "1" ? 1 : 0), PDO::PARAM_INT);
// Passing a 1 or 0 with PARAM_BOOL always returns false
$stmt->bindValue(":isRemindedWeekly", ($_POST["IsRemindedWeekly"] == "1" ? 1 : 0), PDO::PARAM_BOOL);
// Passing a true or false with PARAM_INT always returns false
$stmt->bindValue(":isRemindedWeekly", $_POST["IsRemindedWeekly"], PDO::PARAM_INT);
// Passing a true or false with a PARAM_BOOL always returns true
$stmt->bindValue(":isRemindedWeekly", $_POST["IsRemindedWeekly"], PDO::PARAM_BOOL);
When it expects PDO::PARAM_BOOL, you probably should provide it with boolean:
$_POST["IsRemindedWeekly"] == "1" // this evaluates to boolean
While it is generally easier to change the column to TINYINT and use 0 and 1, because you'd have define the data-type for bindValue() as int $data_type = PDO::PARAM_BOOL. This might be a matter of taste, because there is nothing wrong with either approach - but casting to boolean on read is less effort, than on write.
What you get from the $_POST will always be of data-type string.
eg. for int you'd have to type-cast: (int) $_POST["IsRemindedWeekly"].
And you were missing the the type-cast to boolean, as I've suggested it above:
$stmt->bindValue(":isRemindedWeekly", $_POST["IsRemindedWeekly"] == "1", PDO::PARAM_BOOL);
Also see the PHP manual for Type Juggling, which is quite essential.
This question already has answers here:
Insert NULL instead of empty string with PDO
(3 answers)
Closed last month.
I searched any possible help that can be found online but still the problem with INSERT NULL using PHP PDO persists.
The script is a csvupload script originally came from here Import CSV into MySQL
To make the story short, Let me present the possible cause..
if($linearray[4]=='Unknown')
$linearray[4]=null;
$linemysql = implode("','",$linearray);
$linemysql = "'".$linemysql."'";
$setsu->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$tsuika = $setsu->prepare("INSERT INTO tablename (SubAgentID, BookID, AgentID, SubAgentName, Risk, Area, CurrentBalance) VALUES ($linemysql)");
$tsuika -> bindValue(':Risk', null, PDO::PARAM_INT);
$tsuika ->execute();
Looking the code above, I explicitly set the field values on the prepare statment.
On phpmyadmin the Risk field accepts NULL, set the default value to NULL, and has no problems. But when doing INSERT with PHP the value it gets is 0. Why?
Before Inserting, I echoed it and if the field $linearray[4] contains Unknown, it converts it to NULL yielding, '' for that part.
table structure
CREATE TABLE IF NOT EXISTS `subagentdb` (
`SubAgentID` int(10) NOT NULL AUTO_INCREMENT,
`BookID` int(10) NOT NULL,
`AgentID` int(10) NOT NULL,
`SubAgentName` varchar(30) NOT NULL,
`Risk` float DEFAULT NULL,
`Area` varchar(20) NOT NULL,
`CurrentBalance` float NOT NULL,
PRIMARY KEY (`SubAgentID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ;
You're binding the value explicitly as PDO::PARAM_INT. Whatever value you pass will be cast to an int because of that. null casts to 0.
To actually bind an SQL NULL value, you need to bind the value as PDO::PARAM_NULL.
just use PDO::PARAM_NULL instead of PDO::PARAM_INT ? I think the NULL is converted to 0 (INT) instead of null value
If you back-up a and then restore the table, the null value becomes 0. The only way I found to correct this is after the create table, add "UPDATE table SET foo to null WHERE foo = 0".
My query returns with null in my php code , but when I enter the same query into phpmyadmin it returns the row to which it belongs. Here is the database I am using
CREATE TABLE `payment`.`users`(
`u_id` int(12) NOT NULL AUTO_INCREMENT,
`email` varchar(255) NOT NULL,
`passwd` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY (`email`)
) ENGINE=MyISAM;
and here is the code i am using that is returning null when it clearly works in phpmyadmin.
function getUserId($email, $passwd) {
$mysqli = db_connect();
$query = "SELECT `u_id` FROM `payment`.`users` WHERE `email`='$email' AND `passwd`='$passwd' ORDER BY 1";
if ($stmt = $mysqli->prepare($query)) {
/* execute query */
$stmt->execute();
$stmt->bind_result($u_id);
while ($stmt->fetch()) {
return $u_id;
}
}
}
The thing is that you are using variables in your php code to set the values. In phpMyAdmin you're inserting values directly, therefore the problem may be in the values inserted.
First of all use PDO's bindParam() or mysqli's bind_param() statements as they sanitize inputs and help you avoid SQL Injections.
Second good thing about using prepared statements and binding params is that you can specify the type of the data being binded to to the query which in most cases will fix such problems. Though in your case you're probably inserting strings.
I have a table like this:
CREATE TABLE IF NOT EXISTS `session` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`token` varchar(32) NOT NULL,
`profile` varchar(1000) NOT NULL,
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=41 ;
and some data in this table:
(38, '395d5feaf28df01aafe0781a7f34acbe', 'a:3:{s:2:"id";s:1:"2";s:8:"username";s:7:"wanmeng";s:12:"created_time";s:19:"2011-11-18 19:37:33";}', '2011-12-03 14:14:35'),
(39, '0e0ca06ed9ad86937f190eb9544ac935', 'a:3:{s:2:"id";s:1:"1";s:8:"username";s:6:"delphi";s:12:"created_time";s:19:"2011-11-18 13:29:40";}', '2011-12-03 14:28:36'),
(31, '3cba76b97cf123009632bdaa5a306385', 'a:3:{s:2:"id";s:1:"1";s:8:"username";s:6:"delphi";s:12:"created_time";s:19:"2011-11-18 13:29:40";}', '2011-12-02 15:50:21'),
(30, 'fa356333dd3ee8f1b18b8bf0a827e34c', 'a:3:{s:2:"id";s:1:"1";s:8:"username";s:6:"delphi";s:12:"created_time";s:19:"2011-11-18 13:29:40";}', '2011-12-01 15:32:47')
When I execute the query: SELECT * FROM session WHERE token = false , I expect no result returned, but the mysql returns the results:
39 0e0ca06ed9ad86937f190eb9544ac935 a:3:{s:2:"id";s:1:"1";s:8:"username";s:6:"delphi";... 2011-12-03 22:28:36
30 fa356333dd3ee8f1b18b8bf0a827e34c a:3:{s:2:"id";s:1:"1";s:8:"username";s:6:"delphi";... 2011-12-01 23:32:47
It seems like the boolean value 'false' can match some varchar, but is there any relation between 'fa356333dd3ee8f1b18b8bf0a827e34c' and 'false', why is it so?
In MYSQL, FALSE is not a boolean value, it's an integer, more specifically zero. In fact, MySQL does not have boolean column types (it has BOOL and BOOLEAN but they're mere aliases for TINYINT). So your query is a synonym for:
SELECT * FROM session WHERE token = 0
Since token is a VARCHAR, MySQL needs to convert your strings to number. Run this query and you'll get an idea about the rules:
SELECT
0 + "0001",
0 + "123abc",
0 + "abc123"
As a result, fa356333dd3ee8f1b18b8bf0a827e34c casts to 0 because it starts with a letter, thus the match.
If you want to compare a boolean with a varchar, MySQL has to do some implicit type conversion. MySQL casts the varchar value to a boolean, checking only the first character.
If the character is a character or number 0, then the string is evaluated to 0, thus False.
If the character is a number different than 0, then the string is evaluted to 1, thus True (and not appearing in your result set)
The only thing to do is not to compare a string with a boolean, because it makes no sense.
Is there any reason you're not testing token is null or token like ''? Comparing a varchar to false is a bad idea regardless of whether the DB will catch your mistake or not... a varchar is never false, and false doesn't equal null.
This should be a comment, but I don't have enough reputation... so..
DelphiQin, you said in a comment that you are passing the result of the CI "get()" method to the query parameter. I've been there and I solved by just casting the variable to string before passing to the query:
(string)$my_var
This way, it will use '' (empty string) instead of boolean false.
I hope it helps people with the same problem.
I am trying to dynamically insert 'NULL' into the database using PDO.
TABLE STRUCTURE:
CREATE TABLE IF NOT EXISTS `Fixes` (
`Id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'PK',
`CurrencyId` int(11) NOT NULL COMMENT 'FK',
`MetalId` int(11) NOT NULL COMMENT 'FK',
`FixAM` decimal(10,5) NOT NULL,
`FixPM` decimal(10,5) DEFAULT NULL,
`TimeStamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `CurrencyId` (`CurrencyId`),
KEY `MetalId` (`MetalId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=13 ;
PHP / PDO QUERY:
$sql = 'UPDATE
Fixes
SET
FixAM = :fixAM,
FixPM = :fixPM
WHERE
MetalId IN (SELECT Id FROM Metals WHERE Name = :metal) AND
CurrencyId IN (SELECT Id FROM Currencies Where Id = :currency)';
$stmt = $db->prepare($sql);
for ($i = 0; $i<3; $i++) {
$stmt->execute(array(
':metal' => 'Silver',
':fixAM' => $fix['FixAM'][$i],
':fixPM' => $fix['FixPM'][$i],
':currency' => ($i+1))
);
}
e.g. sometimes, the value for $fix['FixPM'][$i] is sometimes 'NULL'. How do I insert this into the database? When I run the query and then view the data in the database, this record shows 0.0000, and not null.
How do I insert NULL values using PDO? provides a few solutions.
I dont think I can use $stmt->execute(array( ':v1' => null, ':v2' => ... )) as per example because sometimes the item is null, and sometimes not. As such, I need to refer to the variable I have created $fix['FixPM'][$i] and make that null as and when needed
Thanks in advance.
This appears to me to be a(n unreported?) bug in PDO's prepared statement emulation:
the implementation of PDOStatement::execute() eventually invokes pdo_parse_params();
that, in turn, attempts to quote/escape values based on the relevant parameter's data type (as indicated by the $data_type arguments to PDOStatement::bindValue() and PDOStatement::bindParam()—all parameters provided as $input_parameters to PDOStatement::execute() are treated as PDO::PARAM_STR, as stated in the documentation of that function);
string-typed values are escaped/quoted by calling the relevant database driver's quoter() method irrespective of whether they are null: in the case of PDO_MySQL, that's mysql_handle_quoter(), which (eventually) passes the value to either mysqlnd_cset_escape_quotes() or mysql_cset_escape_slashes(), depending on the server's NO_BACKSLASH_ESCAPES SQL mode;
given a null argument, both of those functions return an empty string.
My opinion is that, prior to switching on the parameter's type (in step 2 above), pdo_parse_params() should set the type to PDO::PARAM_NULL if the value is null. However, some might argue that this would prevent type-specific handling of null values where appropriate, in which case the string case (in step 3 above) should definitely handle null values before proceeding with a call to the driver's quoter() method.
As an interim workaround, disabling prepared statement emulation is usually for the best anyway:
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);