mysqli bind_param() expected to be a reference, value given - php

Can't figure out, whats causing error Parameter 3 to mysqli_stmt::bind_param() expected to be a reference, value given in...
PDO
$query = "INSERT INTO test (id,row1,row2,row3) VALUES (?,?,?,?)";
$params = array(1,"2","3","4");
$param_type = "isss";
$sql_stmt = mysqli_prepare ($mysqli, $query);
call_user_func_array('mysqli_stmt_bind_param', array_merge(array($sql_stmt, $param_type), $params));
mysqli_stmt_execute($sql_stmt);
Also tried OOP
OOP
$insert_stmt = $mysqli->prepare($query);
array_unshift($params, $param_type);
call_user_func_array(array($insert_stmt, 'bind_param'), $params);
$insert_stmt->execute();
But same error, only that now Parameter 2 is causing problem.
So, what's wrong with $params? I need $params to be an array of values.

UPDATE
This answer is outdated. Please use the spread operator in newer PHP versions like answered by Stacky.
From php docu:
Care must be taken when using mysqli_stmt_bind_param() in conjunction with call_user_func_array(). Note that mysqli_stmt_bind_param() requires parameters to be passed by reference, whereas call_user_func_array() can accept as a parameter a list of variables that can represent references or values.
And on the page mysqli-stmt.bind-param you have different solutions:
For example:
call_user_func_array(array($stmt, 'bind_param'), refValues($params));
function refValues($arr){
if (strnatcmp(phpversion(),'5.3') >= 0) //Reference is required for PHP 5.3+
{
$refs = array();
foreach($arr as $key => $value)
$refs[$key] = &$arr[$key];
return $refs;
}
return $arr;
}

Introduced in PHP 5.6, you can use the ... operator ("spread operator") to achieve the same result with less trouble:
//object-oriented
$sql_stmt->bind_param($param_type, ...$params);
//procedural
mysqli_stmt_bind_param($sql_stmt, $param_type, ...$params);

When using mysqli in PHP8.1 or higher, you can pass an array of values directly to execute() which makes for a clean and concise code.
$query = "INSERT INTO test (id,row1,row2,row3) VALUES (?,?,?,?)";
$params = [1, "2", "3", "4"];
$stmt = $mysqli->prepare($query);
$stmt->execute($params);
You can also use PDO, which offers an even more concise syntax.

Related

mysqli_stmt_bind_param - expects references [duplicate]

This question already has answers here:
mysqli bind_param() expected to be a reference, value given
(3 answers)
Closed 12 months ago.
I understand that we have to pass references to mysqli_stmt_bind_param. I am doing the following
$ref = refValues($data);
function refValues($arr){
$refs = array();
foreach($arr as $key => $value)
$refs[$key] = &$arr[$key];
var_dump(implode(",", $refs));
return $refs;
return $arr;
}
I am having all of my values in an array. I am using the above function to get the references. Got the above answer from SO
My PHP version is 5.6
I am binding the params in the following way.
mysqli_stmt_bind_param($stmt, $types, $ref);
$stmt is a statement created through mysqli_prepare. It returns error number 0.
$types is nothing but $types = str_pad('',count($data),'s');
I have verified $types data also. It returns expected number of types. i.e ssssssss
If I execute, I am getting the following error.
Only variables should be passed by reference in test.php
I found this solution in SO. I cannot assign 100 variables. I am not thinking that is feasible.
I found another alternative is call_user_func_arrary.
$values = refValues($data);
call_user_func_array(array($stmt, 'bind_param'), $values);
It returns number of bind type doesn't match number of values. It is weird for me. I have verified the array and values. Both counts are matching. I am not aware of internal implementation of call_user_func_array.
Please let me know is there any way to solve this efficiently.
This line
mysqli_stmt_bind_param($stmt, $types, $ref);
means that you have one reference to bind.
Why? Let's see:
first argument is a statement
second argument is a string with types
following arguments are references to values which should be binded.
As you pass one argument (it is $ref) - you are trying to bind only one value. And $ref is not a reference, it is array of values which are refernces. See the difference? Array of references vs reference.
So, you took second approach, and it is a right one:
$values = refValues($data);
call_user_func_array(array($stmt, 'bind_param'), $values);
What's the error here? You didn't pass types $types:
// do not assign anything to a variable
// pass results of `refValues` directly to `call_user_func_array`
call_user_func_array(array($stmt, 'bind_param'), array_merge(array($types), refValues($data)));
What do we do here: we are trying to call $stmt->bind_param and pass to this function arguments as array.
What are the arguments of $stmt->bind_param?
first argument is types ($types)
following arguments are references to values ($values)
Now it should work.
There are two possible ways to avoid this hassle:
Use PDO. Your current problem is only the first out of many WTFs you will have with mysqli. In this particular case it would be as simple and natural as
$stmt = $db->prepare($sql);
$stmt->execute($data);
Okay, you have such a whim of using mysqli. Then, as long as you are using a supported PHP version, you can use a splat or a three dot operator:
$stmt = $db->prepare($sql);
$types = str_repeat('s', count($data));
$statement->bind_param($types, ...$data);
$statement->execute();

How to use Reflection to insert data with mysqli by bind_param method? what is difference of these two arrays?

As bind_param($types, $var1, $var2, $var3,..) method of mysqli_stmt class it gets just a series of $variables after second parameter (I want to pass array there), and the number of $variables is unknown in my case, I want to use Reflection in my insert($data) function. http://php.net/manual/ru/mysqli-stmt.bind-param.php
I do not show the unnecessary part of my function, to avoid confusion...
public function insert($data)
{
$types = 'sss';
$values = array_values($data);
Removed unrelated code
$ref = new ReflectionClass($this->stmt);
$method = $ref->getMethod("bind_param");
//array_unshift($values,$types); 1-option
$values = array($types,'alex','alex#code.com','cats'); 2-option
$method->invokeArgs($this->stmt, $values);
$done = $this->stmt->execute();
$this->stmt->close();
return $done;
}
As shown in
$method = $ref->getMethod("bind_param");
$method->invokeArgs($this->stmt, $values);
In this part I use Reflection to pass array to second parameter of bind_param() method of $this->$stmt object.
$method->invokeArgs($this->stmt, $values);
It doesn`t make mysqli insert into table with 1-option.
But mysqli inserts data when I use 2-option. Why? I have to use with 1-option as number of parameters is unknown.
How can I benefit from Reflection and mysqli it?
What is the difference between those two options(arrays)?
You can use splat operator (PHP version >= 5.6):
public function insert($data)
{
$stmt = $this->link->prepare($sql);
$stmt->bind_param(str_repeat('s', count($data), ...$data);
$stmt->execute();
}

PDO bindParam not working in foreach

I am using PDO for an application but getting a problem for PDO bindParam(). I have an array and I want to use the values of array for PDO bindParam() using for loop or foreach() but an unexpected result is getting by foreach(). When I used bindParam() in for loop, it worked fine. What I tried was
$con = $this->connection();
$stmt = $con->prepare($sql);
for($i = 0; $i < count($params); $i++){
$stmt->bindParam($i + 1, $params[$i], PDO::PARAM_STR, 10);
}
$stmt->execute();
$result = $stmt->fetchAll();//$result is OK
But when I used bindParam() in foreach() then I got an empty array() as result. Below the codes
$con = $this->connection();
$stmt = $con->prepare($sql);
foreach($params as $key=>$val){ //Here
$stmt->bindParam($key + 1, $val, PDO::PARAM_STR, 10);
}
$stmt->execute();
$result = $stmt->fetchAll(); //$result is an empty array
I'm wondering why this happened. I can't find out the reason. Any information will be appreciated.
EDIT : I solved my problem using bindValue() instead.
use bindValue() instead of bindParam(). bindParam() binds to a reference, so when you execute the query all the parameters use the last value of $val.
If you already have the items in an array, there's no reason to call $stmt->bindParam in a loop; just do:
$con = $this->connection();
$stmt = $con->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetchAll();
Per the PHP documentation:
Execute the prepared statement. If the prepared statement included
parameter markers, you must either:
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
or pass an array of input-only parameter values

Pass Variable as reference to mysqli_stmt::bind_param() [duplicate]

Can't figure out, whats causing error Parameter 3 to mysqli_stmt::bind_param() expected to be a reference, value given in...
PDO
$query = "INSERT INTO test (id,row1,row2,row3) VALUES (?,?,?,?)";
$params = array(1,"2","3","4");
$param_type = "isss";
$sql_stmt = mysqli_prepare ($mysqli, $query);
call_user_func_array('mysqli_stmt_bind_param', array_merge(array($sql_stmt, $param_type), $params));
mysqli_stmt_execute($sql_stmt);
Also tried OOP
OOP
$insert_stmt = $mysqli->prepare($query);
array_unshift($params, $param_type);
call_user_func_array(array($insert_stmt, 'bind_param'), $params);
$insert_stmt->execute();
But same error, only that now Parameter 2 is causing problem.
So, what's wrong with $params? I need $params to be an array of values.
UPDATE
This answer is outdated. Please use the spread operator in newer PHP versions like answered by Stacky.
From php docu:
Care must be taken when using mysqli_stmt_bind_param() in conjunction with call_user_func_array(). Note that mysqli_stmt_bind_param() requires parameters to be passed by reference, whereas call_user_func_array() can accept as a parameter a list of variables that can represent references or values.
And on the page mysqli-stmt.bind-param you have different solutions:
For example:
call_user_func_array(array($stmt, 'bind_param'), refValues($params));
function refValues($arr){
if (strnatcmp(phpversion(),'5.3') >= 0) //Reference is required for PHP 5.3+
{
$refs = array();
foreach($arr as $key => $value)
$refs[$key] = &$arr[$key];
return $refs;
}
return $arr;
}
Introduced in PHP 5.6, you can use the ... operator ("spread operator") to achieve the same result with less trouble:
//object-oriented
$sql_stmt->bind_param($param_type, ...$params);
//procedural
mysqli_stmt_bind_param($sql_stmt, $param_type, ...$params);
When using mysqli in PHP8.1 or higher, you can pass an array of values directly to execute() which makes for a clean and concise code.
$query = "INSERT INTO test (id,row1,row2,row3) VALUES (?,?,?,?)";
$params = [1, "2", "3", "4"];
$stmt = $mysqli->prepare($query);
$stmt->execute($params);
You can also use PDO, which offers an even more concise syntax.

Trying to create a query function for PDO

As I am writing a script, I am typing $db->prepare()'s and $stmt->bindParam()'s constantly. I am looking for a way to consolidate it all in a function. This is what I have so far.
$sql = "SELECT (name, email) FROM users WHERE VALUES (:name, :email)"
$values = array(':name' => 'my_name', ':email' => 'blahblah#example.com', );
function db_query($sql, $values) {
global $db; //Database object
$stmt = $db->prepare($sql);
foreach($values as $placeholder => $value) {
$stmt->bindParam($placeholder, $value);
}
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
Would this be sufficient for most queries? Is this a secure way to do this?
I just want the query to run and return whatever it returns (NULL, values, error, etc...).
Thanks.
Your code will not work as expected because bindParam() binds the placeholder name (first argument) to the variable reference present in the second argument.
Using your example, this would result in all parameters set to blahblah#example.com as it is the last $value in the loop.
As mentioned in the comments, simply use $stmt->execute($values). See http://php.net/manual/en/pdostatement.execute.php
If you really want to continue with your loop, use PDOStatement::bindValue() instead.

Categories