PDO Invalid Boolean Parameter [duplicate] - php

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.

Related

BindValue does not accept false value

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/

Why am I getting an SQL error when trying to insert a null?

Ok when trying to execute the following insert I'm getting an error
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near '2, 3, 4, 5)' at line 1
$insertSQL = sprintf("INSERT INTO applicants (id_file, address_file, photo, transcript, essay1, essay2) VALUES (%s, %s, %s, %s, %s, %s)",
$passport_file,
$address_file,
$photo_file,
$transcript_file,
$essay1_file,
$essay2_file);
mysqli_select_db($STCi, $database_STC);
$Result1 = mysqli_query($STCi, $insertSQL) or die(mysql_error($STCi));
Those variables are being set using the following code
$_FILES['id_file']['error'] == UPLOAD_ERR_OK?$passport_file=filesDB('id_file'):$passport_file = NULL;
$_FILES['address_file']['error'] == UPLOAD_ERR_OK?$address_file = filesDB('address_file'):$address_file = NULL;
$_FILES['photo']['error'] == UPLOAD_ERR_OK?$photo_file = filesDB('photo'):$photo_file = NULL;
$_FILES['transcript']['error'] == UPLOAD_ERR_OK?$transcript_file = filesDB('transcript'):$transcript_file = NULL;
$_FILES['essay1']['error'] == UPLOAD_ERR_OK?$essay1_file = filesDB('essay1'):$essay1_file = NULL;
$_FILES['essay2']['error'] == UPLOAD_ERR_OK?$essay2_file = filesDB('essay2'):$essay2_file = NULL;
filesDB is my own function I'm running to rename the uploaded files and move them into the correct locations and any that are running through that are fine. The problem comes out with 'address_file' as it is an optional file and whenever nothing is uploaded for it I get the error.
So basically MySQL is throwing an error when I'm trying to insert NULL, or am I missing something obvious?
CREATE TABLE `applicants` (
`applicant_id` int(11) NOT NULL AUTO_INCREMENT,
`id_file` varchar(200) CHARACTER SET latin1 DEFAULT NULL,
`address_file` varchar(200) CHARACTER SET latin1 DEFAULT NULL,
`photo` varchar(200) CHARACTER SET latin1 DEFAULT NULL,
`name_change` varchar(200) CHARACTER SET latin1 DEFAULT NULL,
`transcript` varchar(200) CHARACTER SET latin1 DEFAULT NULL,
`english_result` varchar(200) CHARACTER SET latin1 DEFAULT NULL,
`essay1` varchar(200) CHARACTER SET latin1 DEFAULT NULL,
`essay2` varchar(200) CHARACTER SET latin1 DEFAULT NULL,
`stage` varchar(20) DEFAULT 'New',
`date_applied` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`applicant_id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
use a prepared stamement instead of manually creating a query with sprintf:
if ($stmt = mysqli_prepare($STCi, "INSERT INTO applicants
(id_file, address_file, photo, transcript, essay1, essay2)
VALUES (?, ?, ?, ?, ?, ?)"))
{
mysqli_stmt_bind_param($stmt, "ssssss",
$passport_file,
$address_file,
$photo_file,
$transcript_file,
$essay1_file,
$essay2_file);
mysqli_stmt_execute($stmt) or die(mysql_error($STCi));;
}
You're doing an sprintf, and inserting 'NULL', meaning you have a PHP varaible that is NULL.
Your SQL query should look like this after the sprintf:
INSERT INTO applicants (id_file, address_file, photo, transcript, essay1, essay2)
VALUES (null, 2,3,4,5,6)"
but it looks like this:
INSERT INTO applicants (id_file, address_file, photo, transcript, essay1, essay2)
VALUES ( , 2,3,4,5,6)"
And that's an error.
To fix this, you could actually insert the string null here (if you insert it without ', it will not be seen as a string, as you are not using prepared statements). So you query would look like so:
INSERT INTO applicants (id_file, address_file, photo, transcript, essay1, essay2)
VALUES ( null , 2,3,4,5,6)"
Do this by not assiging NULL to the variable, but just assign 'null'. Verify by first echoing your query. It should have the null in it wihtout any quotes.
A better method is to use actual prepared statements: http://php.net/manual/en/mysqli.prepare.php
I think you are confusing the php null value and the mysql null value - they arent the same thing. I think you want something like:
$_FILES['id_file']['error'] == UPLOAD_ERR_OK?$passport_file=filesDB('id_file'):$passport_file = 'NULL';
Note I have quoted the "null". This will put a text null into the sql statement, which will then be interpreted as the keyword 'null' in mysql.
If you leave the php assignment as the value null then a sort of blanky thing is passed to mysql, when it wants the text string 'null' :)
in order to insert null values you should be using prepared statements
$stmt = $STCi->prepare("INSERT INTO applicants (id_file, address_file, photo, transcript, essay1, essay2) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->bind_param("ssssss",
$passport_file,
$address_file,
$photo_file,
$transcript_file,
$essay1_file,
$essay2_file);
$stmt->execute();

Php PDO: Why does Inserting NULL yields to 0 [duplicate]

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

Debug PDO mySql insert NULL into database instead of empty

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

mysql_affected_rows Returns False On Successful Query?

I am having a difficult time sorting through this PHP/MySQL issue. Let me show you my database, and explain my situation:
Create table:
CREATE TABLE IF NOT EXISTS `users` (
`id` int(50) NOT NULL AUTO_INCREMENT,
`active` varchar(20) NOT NULL,
`activation` varchar(15) NOT NULL,
`firstName` longtext NOT NULL,
`lastName` longtext NOT NULL,
`passWord` longtext NOT NULL,
`changePassword` text NOT NULL,
`emailAddress1` longtext NOT NULL,
`emailAddress2` longtext NOT NULL,
`emailAddress3` longtext NOT NULL,
`role` longtext NOT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `name` (`firstName`,`lastName`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
Insert a value:
INSERT INTO `users` (
`id` ,
`active` ,
`activation` ,
`firstName` ,
`lastName` ,
`passWord` ,
`changePassword` ,
`emailAddress1` ,
`emailAddress2` ,
`emailAddress3` ,
`role`
) VALUES (
NULL, '1000000000', 'abcdefghijklmno', 'John', 'Smith', '*24D7FB97963C40FE5C56A6672F9560FC8B681508', 'on', 'john#gmail.com', '', '', 'User'
);
Update a value:
$affected = mysql_query(UPDATE users SET passWord = PASSWORD('a9eb42e1b3be829ef42972ea9abab334'), changePassword = 'on' WHERE emailAddress1 = 'john#gmail.com', $dbID);
if (mysql_affected_rows($affected)) {
//Never runs
}
The above UPDATE query executes just fine in my script, phpMyAdmin, and the MySQL terminal. However, mysql_affected_rows($affected) always gives me this error:
Warning: mysql_affected_rows() expects parameter 1 to be resource, boolean given
I know that this means my query failed, but every time I go into the database, I see that the values have been updated.
Removing the parameter from the function appears to clear things up. However, I rather have the identifier as the function parameter, just to be sure what I am referring to, and for code insurance.
Any idea why this might be doing this?
Thank you for your time.
http://php.net/mysql_query
Return Values
...
For other type of SQL statements, INSERT, UPDATE, DELETE, DROP, etc, mysql_query() returns TRUE on success or FALSE on error.
And:
int mysql_affected_rows ([ resource $link_identifier = NULL ] )
This means mysql_affected_rows wants a mysql connection resource as an argument. Not the result of mysql_query, and most certainly not if that result is only true or false. You use it like this:
$successful = mysql_query('UPDATE ...');
if ($successful) {
echo 'Affected rows: ' . mysql_affected_rows();
} else {
echo 'Fail: ' . mysql_error();
}
change:
$affected = mysql_query(UPDATE users SET passWord = PASSWORD('a9eb42e1b3be829ef42972ea9abab334'), changePassword = 'on' WHERE emailAddress1 LIKE 'john#gmail.com', $dbID);
and execute
In my case, it was that the new value of updating was equal to the old value, so no change is made and the result of the mysql_affected_rows() would be 0 or false

Categories