Dynamically binding params Php/Mysqli - php

Hi I have some problems with merging my array and bind my params.
Error Message = Warning: mysqli_stmt::bind_param(): Number of elements
in type definition string doesn't match number of bind variables
in.......
$headline = $_GET['hl'];
$county = $_GET['ca'];
$categories = $_GET['co'];
$query = 'SELECT COUNT(id) FROM main_table';
$queryCond = array();
$stringtype = array();
$variable = array();
if (!empty($headline)) {
$queryCond[] = "headline LIKE CONCAT ('%', ? , '%')";
array_push($stringtype, 's');
array_push($variable, $headline);
}
if (!empty($county)) {
$queryCond[] = "county_id = ?";
array_push($stringtype, 'i');
array_push($variable, $county);
}
if (!empty($categories)) {
$queryCond[] = "categories_id = ?";
array_push($stringtype, 'i');
array_push($variable, $categories);
}
if (count($queryCond)) {
$query .= ' WHERE ' . implode(' AND ', $queryCond);
}
//var_dump($query);
$stmt = $mysqli->prepare($query);
$variable = array_merge($stringtype, $variable);
print_r($variable);
//var_dump($refs);
$refs = array();
foreach($variable as $key => $value)
$refs[$key] = &$variable[$key];
call_user_func_array(array($stmt, 'bind_param'), $refs);

You need change this:
$variable = array_merge($stringtype, $variable);
$refs = array();
foreach($variable as $key => $value)
$refs[$key] = &$variable[$key];
to this:
$variable = array_combine($stringtype, $variable);
Because array_combine() create an array by using one array for keys and another for its values.
Read more at:
http://php.net/manual/en/function.array-combine.php

It's a bit late answer, but I had issue with dynamically adding values.
If you have php v +5.6, you can omit this part
$variable = array_merge($stringtype, $variable);
// and $refs
call_user_func_array(array($stmt, 'bind_param'), $refs);
and using ...token introduced in +5.6v.
Here is a fully work example for my case:
// establish mysqli connection
$conn = new mysqli(.....);
$tableName = 'users';
// Types to bind
$type = 'isss';
$fields = ['id','name', 'email', 'created'];
$values = [1, 'name', 'email#test.com', '2018-1-12'];
$sql = "INSERT INTO " . $tableName . " (" . join(',', $fields) . ") VALUES (?,?,?,?)";
$stmt = $conn->prepare($sql);
// Using ...token introduced in php v.5.6 instead of call_user_func_array
// This way references can be omitted, like for each value in array
$stmt->bind_param($type, ...$values);
$stmt->execute();
$stmt->close();

Related

php function to mysqli update

Trying to create a function that would be used to update any row of any table, but I'm getting trouble getting into it.
Data sent in array where the array index is the field name in table and the value is the new value for that index.
For examplpe:
$args["name"] = "NewName";
$args["city"] = "NewCity";
$args["id"] = 4; // row ID to update
What I got:
function create_update_query($table, $keys){
$keys = array_map('escape_mysql_identifier', $keys);
$table = escape_mysql_identifier($table);
$updates = "";
$count = 0;
foreach($keys as $index => $value){
if($index != "id"){
$count++;
if($count == count($keys)-1){
$updates = $updates . "$index = ?";
}else{
$updates = $updates . "$index = ?,";
}
}
}
return "UPDATE $table SET $updates WHERE id = ? LIMIT 1";
}
After that, I have the function to really do the query:
function crud_update($conn, $table, $data){
$sql = create_update_query($table, array_keys($data));
if(prepared_query($conn, $sql, array_values($data))){
$errors [] = "OK";
}else{
$errors [] = "Something weird happened...";
}
}
The function that makes the prepared statement itself:
function prepared_query($mysqli, $sql, $params, $types = ""){
$types = $types ?: str_repeat("s", count($params));
if($stmt = $mysqli->prepare($sql)) {
$stmt->bind_param($types, ...$params);
$stmt->execute();
return $stmt;
} else {
$error = $mysqli->errno . ' ' . $mysqli->error;
echo "<br/>".$error;
}
}
When trying to submit the data with the following criteria:
$args['name'] = "Novo Nome";
$args['field'] = "New Field";
$args['numaro'] = 10101010;
$args['id'] = 4;
//create_update_query("teste_table", $args);
crud_update($link, "teste_table", $args);
Have an error:
1064 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 '1 = ?,2 = ?,3 = ? WHERE id = ? LIMIT 1' at line 1
But if I echo the query created by create_update_query it seems ok:
UPDATE `teste_table` SET name = ?,field = ?,numaro = ? WHERE id = ? LIMIT 1
Any help would be appreciated.
Thanks.
The problem is that as you pass the keys to create_update_query() as
create_update_query($table, array_keys($data));
Using array_keys() will just take the key names, so the $keys parameter is just a list of the field names as something like ...
Array(
0=> 'name',
1 =>'field',
2 =>'numaro'
)
You then extract the data using
foreach($keys as $index => $value){
and build your SQL with
$updates = $updates . "$index = ?";
so at this point, the indexes are the numeric value, so change these lines to...
$updates = $updates . "$value = ?";
which is the name of the field.
With the various other changes, I would suggest the code should be...
foreach($keys as $value){
if($value != "id"){
$updates = $updates . "$index = ?,";
}
}
$updates = rtrim($updates, ",");
return "UPDATE $table SET $updates WHERE id = ? LIMIT 1";

mysqli_prepare query returning false

I am attempting to bind params to a sql statement using call_user_func_array as describe on Dynamically Bind Params in Prepared Statements with MySQLi; however, my mysqli_prepare keeps returning false.
Here is my data function that is called to store data:
function storeData($form_data, $table_name, $cxn){
if(!is_array($form_data)){
return false;
exit();
}
$types = str_repeat("s", count($form_data));
$params = array();
$params[] = &$types;
$keys = array_keys($form_data);
$values = array_values($form_data);
for ($i = 0; $i < count($values); $i++) {
$params[] = &$values[$i];
}
$sql = "INSERT INTO $table_name (" . implode(',', $keys) . ") VALUES (" .
implode(',', array_fill(0, count($values), '?')) . ")
ON DUPLICATE KEY UPDATE ";
$updates = implode(',', array_map(function($col) {
return "$col = VALUES($col)";
}, $keys));
$sql .= $updates;
if($stmt = mysqli_prepare($cxn, $sql)){
call_user_func_array(array($stmt, 'bind_param'), $params);
return mysqli_stmt_execute($stmt);
}
Here is my $sql string at time of prepare:
$sql"INSERT INTO interest (Baseball,Basketball,Camping,Canoeing,Cycling,Football,Gaming,Golf,Hiking,Parks,Photography,Runway,Skydiving,Soccer,Username) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE Baseball = VALUES(Baseball),Basketball = VALUES(Basketball),Camping = VALUES(Camping),Canoeing = VALUES(Canoeing),Cycling = VALUES(Cycling),Football = VALUES(Football),Gaming = VALUES(Gaming),Golf = VALUES(Golf),Hiking = VALUES(Hiking),Parks = VALUES(Parks),Photography = VALUES(Photography),Runway = VALUES(Runway),Skydiving = VALUES(Skydiving),Soccer = VALUES(Soccer),Username = VALUES(Username)"
Here is my $params and $key outputs:
$keysarray[15]
$keys[0]"Baseball"
$keys[1]"Basketball"
$keys[2]"Camping"
$keys[3]"Canoeing"
$keys[4]"Cycling"
$keys[5]"Football"
$keys[6]"Gaming"
$keys[7]"Golf"
$keys[8]"Hiking"
$keys[9]"Parks"
$keys[10]"Photography"
$keys[11]"Runway"
$keys[12]"Skydiving"
$keys[13]"Soccer"
$keys[14]"Username"
$paramsarray[16]
$params[0]"sssssssssssssss"
$params[1]"0"
$params[2]"0"
$params[3]"0"
$params[4]"0"
$params[5]"0"
$params[6]"0"
$params[7]"0"
$params[8]"0"
$params[9]"0"
$params[10]"0"
$params[11]"0"
$params[12]"0"
$params[13]"0"
$params[14]"0"
$params[15]"test0613"
$valuesarray[15]
$values[0]"0"
$values[1]"0"
$values[2]"0"
$values[3]"0"
$values[4]"0"
$values[5]"0"
$values[6]"0"
$values[7]"0"
$values[8]"0"
$values[9]"0"
$values[10]"0"
$values[11]"0"
$values[12]"0"
$values[13]"0"
$values[14]"test0613"
There error existed in a column i was attempting to map which did not exist. The error procedure was found here, which allowed me to produce fatal errors that noted a column did not exist in the table I was referencing.

php - number of elements and bind variable mismatch

I seem to be getting an error message of the number of elements in type definition string not matching the number of bind variables.
<?php
function addToTable($data){
$columns = array_keys($data);
$keys = implode(", ", $columns);
$info = array_values($data);
$values = implode(", ", $info);
$preholder = [];
foreach($data as $count){
array_push($preholder,"?");
}
$placeholder = implode(", ", $preholder);
$sql = "INSERT INTO guest ($keys) VALUES ($placeholder)";
$types = [];
foreach($data as $x=>$y){
if(is_numeric($y)){
array_push($types,"i");
}
elseif(gettype($y) == "string"){
array_push($types,"s");
}
}
$types = implode("",$types);
$statement = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($statement, '$types', $values);
$results = mysqli_stmt_execute($statement);
mysqli_close($conn);
return $results;
}
?>
The only possible thing i can think of is in the bind function is actually wanting a number of values after the $type instead of an variable with the listing of values. I would like to keep this working in a way that don't have to manually change it every time.

Array in a select query

I have the following:
<?php
$array = join(',', $ids); // this prints 3,4,6,7,8
$stmt = $cxn->prepare('SELECT * FROM comments WHERE id IN (?)');
$stmt->bind_param('i', $array);
$stmt->execute();
?>
However, when I have it print the results, it only shows the comments from the first id (3) and not the others. What's wrong?
$arrayCount = count($ids);
$binders = array_fill(0, $arrayCount, '?');
// Create an array of references to the values we want to bind
$bindValues = array();
foreach($ids as $key => $id)
$bindValues[$keys] = &$ids[$key];
// Build SQL statement with the necessary number of bind placeholders
$stmt = $cxn->prepare(
'SELECT * FROM comments WHERE id IN (' . implode(',', $binders) . ')'
);
// Bind each value (has to be done by reference)
call_user_func_array(array($stmt, "bind_param"), $bindValues));
$stmt->execute();
I believe for this to work as intended, you have to directly substitute the values into the string:
$idString = '';
foreach($ids as $id) {
$idString .= $id . ',';
}
$idString = substr($idString, 0, -1);
$stmt = $cxn->prepare("SELECT * FROM comments WHERE id IN (".$idstring.")");
$stmt->execute();
Unfortunately, this can then open you up to SQL injection attacks.
Bind them to a string.
$idString = '';
foreach($ids as $id) {
$idString .= $id . ',';
}
$idString = substr($idString, 0, -1);
$stmt = $cxn->prepare('SELECT * FROM comments WHERE id IN (?)');
$stmt->bind_param('s', $idString);
$stmt->execute();

Make this function work with prepare

I have seen this function online to bring a basic support for named parameters for MySQli:
function parseNamedParams(&$queryStr, &$params)
{
$array = array();
if ($c = preg_match_all('/(:\w+)/is', $queryStr, $matches)) { // To match words starting with colon
$list = $matches[0]; // $matches is two-dimensional array, we only need first element
foreach($list as $value) { // We'll replace each parameter in the query string with a '?' (as to comply with mysqli), and make sure the value is in the correct order.
$queryStr = str_replace($value, '?', $queryStr);
$array[] = $params[$value];
}
$params = $array;
}
}
I've been trying to use it:
$DB = new mysqli("host","user","pass","db");
$Query = "SELECT uname FROM test WHERE uname = :user";
$Params = array (
":user" => "Sophie"
);
$Bind = parseNamedParams($Query, $Params);
$SQL = $DB->prepare($Bind);
$SQL->execute();
$SQL->bind_result($Username);
$SQL->fetch();
$SQL->close();
But alas, this does not work
Update
Forgot to include the error message:
Fatal error: Call to a member function execute() on a non-object in
C:\xampp\htdocs\index.php on line 25
If your looking for PDO Style prepared statements, then switch to PDO... But if you really insist on doing this, then I have the following solution:
function Named_Params ($Query, $Params,$DBLink){
$New_Param = array_values($Params);
$Count = 0;
if (preg_match_all('/(:\w+)/is',$Query,$Match)){
$List = $Match[0];
foreach ($List AS $Value){
$Secure_Var = $DBLink->real_escape_string($New_Param[$Count]);
$Query = str_replace($Value,$Secure_Var, $Query);
$Count++;
}
}
return $Query;
}
$DB = new mysqli("","","","");
$Query = "SELECT uname FROM test WHERE uname = ':user'";
$Params = array (
":user" => "Sophie"
);
$Input = Named_Params($Query,$Params,$DB);
$Query = $DB->prepare($Input);
$Query->execute();
$Query->bind_result($Username);
$Query->fetch();
$Query->close();
echo $Name;
Hopefully this is what your looking for

Categories