Related
I'm using this code and I'm beyond frustration:
try {
$dbh = new PDO('mysql:dbname=' . DB . ';host=' . HOST, USER, PASS);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}
catch(PDOException $e)
{
...
}
$stmt = $dbh->prepare('INSERT INTO table(v1, v2, ...) VALUES(:v1, :v2, ...)');
$stmt->bindParam(':v1', PDO::PARAM_NULL); // --> Here's the problem
PDO::PARAM_NULL, null, '', all of them fail and throw this error:
Fatal error: Cannot pass parameter 2 by reference in /opt/...
You need to use bindValue, not bindParam
bindParam takes a variable by reference, and doesn't pull in a value at the time of calling bindParam. I found this in a comment on the PHP docs:
bindValue(':param', null, PDO::PARAM_INT);
P.S. You may be tempted to do this bindValue(':param', null, PDO::PARAM_NULL); but it did not work for everybody (thank you Will Shaver for reporting.)
When using bindParam() you must pass in a variable, not a constant. So before that line you need to create a variable and set it to null
$myNull = null;
$stmt->bindParam(':v1', $myNull, PDO::PARAM_NULL);
You would get the same error message if you tried:
$stmt->bindParam(':v1', 5, PDO::PARAM_NULL);
When using INTEGER columns (that can be NULL) in MySQL, PDO has some (to me) unexpected behaviour.
If you use $stmt->execute(Array), you have to specify the literal NULL and cannot give NULL by variable reference.
So this won't work:
// $val is sometimes null, but sometimes an integer
$stmt->execute(array(
':param' => $val
));
// will cause the error 'incorrect integer value' when $val == null
But this will work:
// $val again is sometimes null, but sometimes an integer
$stmt->execute(array(
':param' => isset($val) ? $val : null
));
// no errors, inserts NULL when $val == null, inserts the integer otherwise
Tried this on MySQL 5.5.15 with PHP 5.4.1
For those who still have problems (Cannot pass parameter 2 by reference), define a variable with null value, not just pass null to PDO:
bindValue(':param', $n = null, PDO::PARAM_INT);
Hope this helps.
I had the same problem and I found this solution working with bindParam :
bindParam(':param', $myvar = NULL, PDO::PARAM_INT);
If you want to insert NULL only when the value is empty or '', but insert the value when it is available.
A) Receives the form data using POST method, and calls function insert with those values.
insert( $_POST['productId'], // Will be set to NULL if empty
$_POST['productName'] ); // Will be to NULL if empty
B) Evaluates if a field was not filled up by the user, and inserts NULL if that's the case.
public function insert( $productId, $productName )
{
$sql = "INSERT INTO products ( productId, productName )
VALUES ( :productId, :productName )";
//IMPORTANT: Repace $db with your PDO instance
$query = $db->prepare($sql);
//Works with INT, FLOAT, ETC.
$query->bindValue(':productId', !empty($productId) ? $productId : NULL, PDO::PARAM_INT);
//Works with strings.
$query->bindValue(':productName',!empty($productName) ? $productName : NULL, PDO::PARAM_STR);
$query->execute();
}
For instance, if the user doesn't input anything on the productName field of the form, then $productName will be SET but EMPTY. So, you need check if it is empty(), and if it is, then insert NULL.
Tested on PHP 5.5.17
Good luck,
Several answers have given examples of what you should do. But they haven't really explained why you should do one of those things.
The bindParam method is meant to be used with something like a loop (or just repeated statements). It binds a variable reference. So something like
$stmt = $dbh->prepare('INSERT INTO t1 (v1) VALUES(:v1)');
$stmt->bindParam(':v1', $i, PDO::PARAM_INT);
for ($i = 0; $i < 10; $i++) {
$stmt->execute();
}
Would insert values 0 through 9 in a table.
That's obviously a very simple example that could be implemented in other, more efficient ways. You could have more complex logic here. But the basic idea is that you bind a reference to a variable and then you can change the value of the variable.
You can get around the need for a reference by creating a variable before calling bindParam. But in your case, you don't particularly want to bind to a variable reference. You just want to bind a value. So go ahead and do exactly that with bindValue.
You can mostly just use bindValue. But to show why both methods exist, let's rewrite the previous example to use bindValue instead of bindParam:
$stmt = $dbh->prepare('INSERT INTO t1 (v1) VALUES(:v1)');
for ($i = 0; $i < 10; $i++) {
$stmt->bindValue(':v1', $i, PDO::PARAM_INT);
$stmt->execute();
}
This will work, but you have to call bindValue on every iteration of the loop whereas you only needed to call bindParam once. But you aren't doing anything like that, so you can just
$stmt->bindValue(':v1', null, PDO::PARAM_INT);
And everything will work, as stated in the accepted answer. Because you want to bind a value, not a variable reference.
Based on the other answers but with a little more clarity on how to actually use this solution.
If for example you have an empty string for a time value but you want to save it as a null:
if($endtime == ""){
$db->bind(":endtime",$endtime=NULL,PDO::PARAM_STR);
}else{
$db->bind("endtime",$endtime);
}
Notice that for time values you would use PARAM_STR, as times are stored as strings.
So you just need to add an extra If statement that properly changes your variable to NULL before you call bindParam(). Here is an example that I figured out for my situation (I was stuck on this for days trying to INSERT a new DB record with a NULL value for one column):
if ($this->companyid == 'NULL' || $this->companyid == NULL) {
$this->companyid = NULL;
$this->companyname = NULL;
$stmt->bindParam(':companyid', $this->companyid);
$stmt->bindParam(':companyname', $this->companyname);
} else {
$stmt->bindParam(':companyid', $this->companyid);
$stmt->bindParam(':companyname', $this->companyname);
}
Try This.
$stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null
In my case I am using:
SQLite,
prepared statements with placeholders to handle unknown number of fields,
AJAX request sent by user where everything is a string and there is no such thing like NULL value and
I desperately need to insert NULLs as that does not violates foreign key constrains (acceptable value).
Suppose, now user sends with post: $_POST[field1] with value value1 which can be the empty string "" or "null" or "NULL".
First I make the statement:
$stmt = $this->dbh->prepare("INSERT INTO $table ({$sColumns}) VALUES ({$sValues})");
where {$sColumns} is sth like field1, field2, ... and {$sValues} are my placeholders ?, ?, ....
Then, I collect my $_POST data related with the column names in an array $values and replace with NULLs:
for($i = 0; $i < \count($values); $i++)
if((\strtolower($values[$i]) == 'null') || ($values[$i] == ''))
$values[$i] = null;
Now, I can execute:
$stmt->execute($values);
and among other bypass foreign key constrains.
If on the other hand, an empty string does makes more sense then you have to check if that field is part of a foreign key or not (more complicated).
i have been trying to insert NULL to my database if the value of input is empty
but i still it insert empty and NULL string
Here's my code
this code returns blank
if (empty($_POST['caller'])){ $caller= NULL; }else{ $caller = mysqli_real_escape_string($con, $_POST['caller']);}
or this
$caller = mysqli_real_escape_string($con, $_POST['caller']);
$caller = !empty($caller_contact) ? "'$caller'" : NULL;
this code returns NULL string
$caller = mysqli_real_escape_string($con, $_POST['caller']);
$caller = !empty($caller_contact) ? "'$caller'" : 'NULL';
or this
if (empty($_POST['caller'])){ $caller= 'NULL'; }else{ $caller = mysqli_real_escape_string($con, $_POST['caller']);}
query
$sql_caller = "INSERT INTO `tblcall_info` VALUES ('','$save_inc_id','$call_time','$call_date','$caller','$caller_contact','$receiver','$device')";
i have also tried changing '$caller' to $caller but its an error.
can anyone help?. thanks
You can try this way:
remove single invated comma from query and set them to query it will surely work for you
if (empty($_POST['caller'])){
$caller="NULL";
}else{
$caller=mysqli_real_escape_string($con, $_POST['caller']);
$caller="'$caller'";
}
$sql_caller = "INSERT INTO `tblcall_info` VALUES ('','$save_inc_id','$call_time','$call_date','$caller','$caller_contact','$receiver','$device')";
Try this method in the $sql_caller string:
INSERT INTO table_name (column1,column2,...) VALUES(value1,value2,...);
And skip the column & it's value, which you want to be set as NULL.
I have a prepared statement to store in my db some data coming from an API:
$sql = "INSERT INTO `standings` (`league_id`, `season`, `position`, `team_id`, `played`, `playedathome`, `playedaway`, `won`, `draw`, `lost`, `numberofshots`, `yellowcards`, `redcards`, `goals_for`, `goals_against`, `points`)
VALUES (:league_id, :season, :position, :team_id, :played, :playedathome, :playedaway, :won, :draw, :lost, :numberofshots, :yellowcards, :redcards, :goals_for, :goals_against, :points)
ON DUPLICATE KEY UPDATE `league_id`=:league_id, `season`=:season, `position`=:position, `team_id`=:team_id, `played`=:played, `playedathome`=:playedathome, `playedaway`=:playedaway, `won`=:won, `draw`=:draw, `lost`=:lost, `numberofshots`=:numberofshots, `yellowcards`=:yellowcards, `redcards`=:redcards, `goals_for`=:goals_for, `goals_against`=:goals_against, `points`=:points";
$prep = $pdo->prepare($sql);
$prep->bindParam(':league_id', $league_id);
$prep->bindParam(':season', $season);
$prep->bindParam(':position', $position);
$prep->bindParam(':team_id', $team_id);
$prep->bindParam(':played', $played);
$prep->bindParam(':playedathome', $playedathome);
$prep->bindParam(':playedaway', $playedaway);
$prep->bindParam(':won', $won);
$prep->bindParam(':draw', $draw);
$prep->bindParam(':lost', $lost);
$prep->bindParam(':numberofshots', $numberofshots);
$prep->bindParam(':yellowcards', $yellowcards);
$prep->bindParam(':redcards', $redcards);
$prep->bindParam(':goals_for', $goals_for);
$prep->bindParam(':goals_against', $goals_against);
$prep->bindParam(':points', $points);
foreach($result->TeamLeagueStanding as $standing){
$team_id = $standing->Team_Id;
$played = $standing->Played;
$playedathome = $standing->PlayedAtHome;
$playedaway = $standing->PlayedAway;
$won = $standing->Won;
$draw = $standing->Draw;
$lost = $standing->Lost;
$numberofshots = $standing->NumberOfShots;
[etc...]
$prep->execute() or print("PDO execute error: ".$prep->errorInfo()[2]);
The problem is that some leagues don't provide the NumberOfShots value, so $standing->NumberOfShots is an empty string, causing the error:
PDO execute error: Incorrect integer value: '' for column 'numberofshots' at row 1
And that row doesn't get inserted.
How can I make something like
if($numberofshot == "")
$numberofshot = NULL;
or tell PDO to use the default value instead of throwing an error, if the value is incorrect?
http://php.net/manual/en/pdo.setattribute.php
try:
setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING);
If this parameter needs an integer value then you should cast it to integer
like using intval() function.
$numberofshots = intval($standing->NumberOfShots);
If some string comes in $standing->NumberOfShots it will convert it into number that is 0
I am parsing an XML feed into a MYSQL table using simplexml_load_file(). Some of the variables are blank, I would like them to be actual NULL instead of NULL, or is there even a difference?
$xml = simplexml_load_file('cb.xml') or die ('Bad XML File');
foreach($xml->item as $item) {
$name = $item->name;
//Tried
if ($name == '') {
$name = 'NULL';
}
//And
if ($name == '') {
$name = NULL;
}
mysql_query("INSERT INTO cb (name) VALUES ('$name')");
This is because you're giving MySQL a string:
.... ('ANYTHING WITHIN QUOTES IS A STRING')
And the PHP null value, when "casted" to a string, becomes an empty string. So your first try gave ... ('NULL'), and now it gives ... ('').
You must use the NULL keyword inside the query, without quotes, to insert NULL into a database field.
mysql_query("INSERT INTO cb (name) VALUES (" . ($name == null ? "NULL" : "'$name'") . ")");
Oh, and as usual, take care not to get SQL-injected with your unprotected $name variable.
The second variable initialization is correct; the first is just the string 'NULL' (which is not special from PHP's viewpoint). However, you should be using prepared statements (MySQLi_STMT or PDOStatement. If you want to stick with the regular mysql extension, use mysql_real_escape_string
An example with PDO is:
$stmt = $pdo_con->prepare("INSERT INTO cb (name) VALUES (?);");
$stmt->execute(array($name));
This will handle nulls correctly, unlike your current string interpolation.
if you're using more than one value and shorthand if else does work then do this: (we will insert the null data in column 3) * Notice that the single quotes are omitted.. this is because "NULL" cannot be entered in as a string for sql or else it will be a string NULL not an SQL NULL which is what we want.
//condition
if ($col3_var !== NULL)
$col3_var = "'$col3_var'";
else
$col3_var = "NULL"; //SQL will omit the "" here
$sql = "INSERT INTO tablename
(col1, col2, col3...)
VALUES
('$col1_var', '$col2_var', $col3_var)";
$result = mysql_query($sql) or die("Err: " . mysql_error());
I'm using this code and I'm beyond frustration:
try {
$dbh = new PDO('mysql:dbname=' . DB . ';host=' . HOST, USER, PASS);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}
catch(PDOException $e)
{
...
}
$stmt = $dbh->prepare('INSERT INTO table(v1, v2, ...) VALUES(:v1, :v2, ...)');
$stmt->bindParam(':v1', PDO::PARAM_NULL); // --> Here's the problem
PDO::PARAM_NULL, null, '', all of them fail and throw this error:
Fatal error: Cannot pass parameter 2 by reference in /opt/...
You need to use bindValue, not bindParam
bindParam takes a variable by reference, and doesn't pull in a value at the time of calling bindParam. I found this in a comment on the PHP docs:
bindValue(':param', null, PDO::PARAM_INT);
P.S. You may be tempted to do this bindValue(':param', null, PDO::PARAM_NULL); but it did not work for everybody (thank you Will Shaver for reporting.)
When using bindParam() you must pass in a variable, not a constant. So before that line you need to create a variable and set it to null
$myNull = null;
$stmt->bindParam(':v1', $myNull, PDO::PARAM_NULL);
You would get the same error message if you tried:
$stmt->bindParam(':v1', 5, PDO::PARAM_NULL);
When using INTEGER columns (that can be NULL) in MySQL, PDO has some (to me) unexpected behaviour.
If you use $stmt->execute(Array), you have to specify the literal NULL and cannot give NULL by variable reference.
So this won't work:
// $val is sometimes null, but sometimes an integer
$stmt->execute(array(
':param' => $val
));
// will cause the error 'incorrect integer value' when $val == null
But this will work:
// $val again is sometimes null, but sometimes an integer
$stmt->execute(array(
':param' => isset($val) ? $val : null
));
// no errors, inserts NULL when $val == null, inserts the integer otherwise
Tried this on MySQL 5.5.15 with PHP 5.4.1
For those who still have problems (Cannot pass parameter 2 by reference), define a variable with null value, not just pass null to PDO:
bindValue(':param', $n = null, PDO::PARAM_INT);
Hope this helps.
I had the same problem and I found this solution working with bindParam :
bindParam(':param', $myvar = NULL, PDO::PARAM_INT);
If you want to insert NULL only when the value is empty or '', but insert the value when it is available.
A) Receives the form data using POST method, and calls function insert with those values.
insert( $_POST['productId'], // Will be set to NULL if empty
$_POST['productName'] ); // Will be to NULL if empty
B) Evaluates if a field was not filled up by the user, and inserts NULL if that's the case.
public function insert( $productId, $productName )
{
$sql = "INSERT INTO products ( productId, productName )
VALUES ( :productId, :productName )";
//IMPORTANT: Repace $db with your PDO instance
$query = $db->prepare($sql);
//Works with INT, FLOAT, ETC.
$query->bindValue(':productId', !empty($productId) ? $productId : NULL, PDO::PARAM_INT);
//Works with strings.
$query->bindValue(':productName',!empty($productName) ? $productName : NULL, PDO::PARAM_STR);
$query->execute();
}
For instance, if the user doesn't input anything on the productName field of the form, then $productName will be SET but EMPTY. So, you need check if it is empty(), and if it is, then insert NULL.
Tested on PHP 5.5.17
Good luck,
Several answers have given examples of what you should do. But they haven't really explained why you should do one of those things.
The bindParam method is meant to be used with something like a loop (or just repeated statements). It binds a variable reference. So something like
$stmt = $dbh->prepare('INSERT INTO t1 (v1) VALUES(:v1)');
$stmt->bindParam(':v1', $i, PDO::PARAM_INT);
for ($i = 0; $i < 10; $i++) {
$stmt->execute();
}
Would insert values 0 through 9 in a table.
That's obviously a very simple example that could be implemented in other, more efficient ways. You could have more complex logic here. But the basic idea is that you bind a reference to a variable and then you can change the value of the variable.
You can get around the need for a reference by creating a variable before calling bindParam. But in your case, you don't particularly want to bind to a variable reference. You just want to bind a value. So go ahead and do exactly that with bindValue.
You can mostly just use bindValue. But to show why both methods exist, let's rewrite the previous example to use bindValue instead of bindParam:
$stmt = $dbh->prepare('INSERT INTO t1 (v1) VALUES(:v1)');
for ($i = 0; $i < 10; $i++) {
$stmt->bindValue(':v1', $i, PDO::PARAM_INT);
$stmt->execute();
}
This will work, but you have to call bindValue on every iteration of the loop whereas you only needed to call bindParam once. But you aren't doing anything like that, so you can just
$stmt->bindValue(':v1', null, PDO::PARAM_INT);
And everything will work, as stated in the accepted answer. Because you want to bind a value, not a variable reference.
Based on the other answers but with a little more clarity on how to actually use this solution.
If for example you have an empty string for a time value but you want to save it as a null:
if($endtime == ""){
$db->bind(":endtime",$endtime=NULL,PDO::PARAM_STR);
}else{
$db->bind("endtime",$endtime);
}
Notice that for time values you would use PARAM_STR, as times are stored as strings.
So you just need to add an extra If statement that properly changes your variable to NULL before you call bindParam(). Here is an example that I figured out for my situation (I was stuck on this for days trying to INSERT a new DB record with a NULL value for one column):
if ($this->companyid == 'NULL' || $this->companyid == NULL) {
$this->companyid = NULL;
$this->companyname = NULL;
$stmt->bindParam(':companyid', $this->companyid);
$stmt->bindParam(':companyname', $this->companyname);
} else {
$stmt->bindParam(':companyid', $this->companyid);
$stmt->bindParam(':companyname', $this->companyname);
}
Try This.
$stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null
In my case I am using:
SQLite,
prepared statements with placeholders to handle unknown number of fields,
AJAX request sent by user where everything is a string and there is no such thing like NULL value and
I desperately need to insert NULLs as that does not violates foreign key constrains (acceptable value).
Suppose, now user sends with post: $_POST[field1] with value value1 which can be the empty string "" or "null" or "NULL".
First I make the statement:
$stmt = $this->dbh->prepare("INSERT INTO $table ({$sColumns}) VALUES ({$sValues})");
where {$sColumns} is sth like field1, field2, ... and {$sValues} are my placeholders ?, ?, ....
Then, I collect my $_POST data related with the column names in an array $values and replace with NULLs:
for($i = 0; $i < \count($values); $i++)
if((\strtolower($values[$i]) == 'null') || ($values[$i] == ''))
$values[$i] = null;
Now, I can execute:
$stmt->execute($values);
and among other bypass foreign key constrains.
If on the other hand, an empty string does makes more sense then you have to check if that field is part of a foreign key or not (more complicated).