How to Use MySQLi Bind_Param Dynamically

How to bind mysqli bind_param arguments dynamically in PHP?

found the answer for mysqli:

public function get_result($sql,$types = null,$params = null)
{
# create a prepared statement
$stmt = $this->mysqli->prepare($sql);

# bind parameters for markers
# but this is not dynamic enough...
//$stmt->bind_param("s", $parameter);

if($types&&$params)
{
$bind_names[] = $types;
for ($i=0; $i<count($params);$i++)
{
$bind_name = 'bind' . $i;
$$bind_name = $params[$i];
$bind_names[] = &$$bind_name;
}
$return = call_user_func_array(array($stmt,'bind_param'),$bind_names);
}

# execute query
$stmt->execute();

# these lines of code below return one dimentional array, similar to mysqli::fetch_assoc()
$meta = $stmt->result_metadata();

while ($field = $meta->fetch_field()) {
$var = $field->name;
$$var = null;
$parameters[$field->name] = &$$var;
}

call_user_func_array(array($stmt, 'bind_result'), $parameters);

while($stmt->fetch())
{
return $parameters;
//print_r($parameters);
}

# the commented lines below will return values but not arrays
# bind result variables
//$stmt->bind_result($id);

# fetch value
//$stmt->fetch();

# return the value
//return $id;

# close statement
$stmt->close();
}

then:

$mysqli = new database(DB_HOST,DB_USER,DB_PASS,DB_NAME);
$output = new search($mysqli);

$sql = "
SELECT *
FROM root_contacts_cfm
ORDER BY cnt_id DESC
";
print_r($output->get_result($sql));

$sql = "
SELECT *
FROM root_contacts_cfm
WHERE root_contacts_cfm.cnt_id = ?
ORDER BY cnt_id DESC
";

print_r($output->get_result($sql,'s',array('1')));

$sql = "
SELECT *
FROM root_contacts_cfm
WHERE root_contacts_cfm.cnt_id = ?
AND root_contacts_cfm.cnt_firstname = ?
ORDER BY cnt_id DESC
";

print_r($output->get_result($sql, 'ss',array('1','Tk')));

mysqli is so lame when comes to this. I think I should be migrating to PDO!

How to use mysqli bind_param dynamically

Yes it's possible and very simple with php5.6, first you need know how many paraments str_repeat(), count() can you help and the unpacking operator (...) too, so this way is possible make binds dynimic.

$params = [10, 50, 51, 99];
$types = str_repeat('i',count($params));

$stmt = $mysqli->prepare("SELECT * FROM t WHERE id IN (?,?,?,?)");
$stmt->bind_param($types, ...$params);
if(!$stmt->excute()){
echo mysqli_error($con);
}

Dynamic variables binding in mysqli bind_param

$stmt = $mysqli->prepare('SELECT * FROM users WHERE lname = ? AND fname = ?');
$stmt->bind_param('ss', $param[0], $param[1]);
$stmt->execute();

//other version
$stmt = $mysqli->prepare('SELECT * FROM users WHERE lname = ? AND fname = ?');
$type = "ss";
$names = array("Maq", "bool");
$params = array(&$type, &$names[0], &$names[1]);

call_user_func_array(array($stmt, 'bind_param'), $params);

Dynamically bind params in $bind_param(); Mysqli

Here is an example that could help ( prepare() function is a class method ).

function prepare( $query, $bind = array() )
{
if ( !$stmt = $this->mysqli->prepare( $query ) )
throw new Exception( 'Query failed: ' . $query . PHP_EOL . $this->mysqli->error );

// if $bind is not an empty array shift the type element off the beginning and call stmt->bind_param() with variables to bind passed as reference
if ( $type = array_shift( $bind ) )
call_user_func_array(
array( $stmt, 'bind_param' ),
array_merge( array( $type ), array_map( function( &$item ) { return $item; }, $bind ) )
);

if ( !$stmt->execute() )
throw new Exception( 'Execute failed: ' . PHP_EOL . $stmt->error );

// choose what to return here ( 'affected_rows', 'insert_id', 'mysqli_result', 'stmt', 'array' )

}

Example of usage:

$db->prepare( "SELECT * FROM user WHERE user_name = ? OR user_email = ?", [ 'ss', $user_name, $user_name ] );

Build SELECT query with dynamic number of LIKE conditions as a mysqli prepared statement

The % wrapping goes around the parameters, not the placeholders.

My snippet will be using object-oriented mysqli syntax instead of the procedural syntax that your code demonstrates.

First you need to set up the necessary ingredients:

  1. the WHERE clause expressions -- to be separated by ORs
  2. the data types of your values -- your values are strings, so use "s"
  3. the parameters to be bound to the prepared statement

I am going to combine #2 and #3 into one variable for simpler "unpacking" with the splat operator (...). The data type string must be the first element, then one or more elements will represent the bound values.

As a logical inclusion, if you have no conditions in your WHERE clause, there is no benefit to using a prepared statement; just directly query the table.

Code: (100% Tested / Successful Code)

$string = "my name";

$conditions = [];
$parameters = [''];
foreach (array_unique(explode(' ', $string)) as $value) {
$conditions[] = "name LIKE ?";
$parameters[0] .= 's';
$parameters[] = "%{$value}%";
}
// $parameters now holds ['ss', '%my%', '%name%']

$query = "SELECT * FROM info";
if ($conditions) {
$stmt = $conn->prepare($query . ' WHERE ' . implode(' OR ', $conditions));
$stmt->bind_param(...$parameters);
$stmt->execute();
$result = $stmt->get_result();
} else {
$result = $conn->query($query);
}
foreach ($result as $row) {
echo "<div>{$row['name']} and whatever other columns you want</div>";
}

For anyone looking for similar dynamic querying techniques:

  • SELECT with dynamic number of values in IN()
  • INSERT dynamic number of rows with one execute() call

A helper function for mysqli that dynamically binds params in prepared statement?

You are on a very right track! Such a function should be an everyday companion for the every PHP programmer using mysqli, but strangely, only few ever have an idea of creating one.

I've had an exactly the same idea once and implemented a mysqli helper function of my own:

function prepared_query($mysqli, $sql, $params, $types = "")
{
$types = $types ?: str_repeat("s", count($params));
$stmt = $mysqli->prepare($sql);
$stmt->bind_param($types, ...$params);
$stmt->execute();
return $stmt;
}

Main differences from your approach

  • the connection is made only once. Your code connects every time it executes a query and this is absolutely NOT what it should do
  • it can be used for any query, not only SELECT. You can check the versatility of the function in the examples section down in the article
  • types made optional as most of time you don't care for the type
  • no bizarre $location variable. Honestly, whatever HTTP stuff should never be a part of a database operation! If you're curious how to properly deal with errors, here is my other article Error reporting in PHP

With your example query it could be used like this

$check = prepared_query($sql, [$id, $mail])->get_result()->fetch_row();

or, if you want a distinct function, you can make it as well

function check_database($mysqli, $sql, $params, $types = "")
{
return prepared_query($mysqli, $sql, $params, $types)->get_result()->fetch_row();
}

and now it can be called as

$check = check_database($sql, [$id, $mail]);

Dynamically generate type definition string for prepared statement

bind_param() actually takes variable arguments, not an array argument. But modern PHP has syntax for turning an array into multiple scalar arguments:

$stmt->bind_param($stmt_param, ...$readingValues); //Binding

This is equivalent to passing the array elements as individual arguments:

$stmt->bind_param($stmt_param, $readingValues[0], $readingValues[1],
$readingValues[2], etc.);

But that's awkward if you don't know how many elements are in the array.


FYI, I like to use PDO instead of mysqli. You don't have to bind anything, just pass the array of values as the argument to execute():

$stmt=$pdo->prepare($val_insert_query); 

$stmt->execute( $readingValues );

I find PDO to be a lot easier. The reason to use mysqli is if you have a lot of legacy code from the mid-2000's that you need to adapt. If you're just starting out, you have no old code. So you might as well adopt PDO to start with.

There's a good tutorial for PDO: https://phpdelusions.net/pdo/

Bind parameters dynamically to a mysqli statement

Easiest solution to generating the placeholders:

function placeholderMarks($count) {
return join(', ', array_fill(0, $count, '?'));
}

Insert the result of this function into the query with placeholderMarks(count($values_columns))

Dynamically bind mysqli_stmt parameters and then bind result

Okay, here is a way to do it:

Edited, to fix bug when fetching multiple rows

$sql = "SELECT `first_name`,`last_name` FROM `users` WHERE `country` =? AND `state`=?";
$params = array('Australia','Victoria');

/*
In my real app the below code is wrapped up in a class
But this is just for example's sake.
You could easily throw it in a function or class
*/

// This will loop through params, and generate types. e.g. 'ss'
$types = '';
foreach($params as $param) {
if(is_int($param)) {
$types .= 'i'; //integer
} elseif (is_float($param)) {
$types .= 'd'; //double
} elseif (is_string($param)) {
$types .= 's'; //string
} else {
$types .= 'b'; //blob and unknown
}
}
array_unshift($params, $types);

// Start stmt
$query = $this->connection->stmt_init(); // $this->connection is the mysqli connection instance
if($query->prepare($sql)) {

// Bind Params
call_user_func_array(array($query,'bind_param'),$params);

$query->execute();

// Get metadata for field names
$meta = $query->result_metadata();

// initialise some empty arrays
$fields = $results = array();

// This is the tricky bit dynamically creating an array of variables to use
// to bind the results
while ($field = $meta->fetch_field()) {
$var = $field->name;
$$var = null;
$fields[$var] = &$$var;
}

$fieldCount = count($fieldNames);

// Bind Results
call_user_func_array(array($query,'bind_result'),$fields);

$i=0;
while ($query->fetch()){
for($l=0;$l<$fieldCount;$l++) $results[$i][$fieldNames[$l]] = $fields[$fieldNames[$l]];
$i++;
}

$query->close();

// And now we have a beautiful
// array of results, just like
//fetch_assoc
echo "<pre>";
print_r($results);
echo "</pre>";
}


Related Topics



Leave a reply



Submit