I am writing a function in which I can do a couple of database actions, in this case an insert data based on a simple array
"insert" => array (
"1" => array (
"tnt_role" => array (
"rolename" => array (
"value" => "administrator",
"notation" => "string"
)
)
),
"2" => array (
"tnt_role" => array (
"rolename" => array (
"value" => "user",
"notation" => "string"
)
)
),
"3" => array (
"tnt_users" => array (
"username" => array (
"value" => "administrator",
"notation" => "string"
),
"userpassword" => array (
"value" => md5('admin', FALSE),
"notation" => "string"
),
"email" => array (
"value" => "someone#something.com",
"notation" => "string"
),
"roleid" => array (
"value" => "1",
"notation" => "int"
)
)
)
)
and here is the specific part of the function
case "insert":
foreach ($tables as $instance => $inserttables) {
foreach ($inserttables as $table => $fields) {
// create a count on the number of fields that are being parsed
$countfields = count($fields);
$sql = "INSERT INTO ". $table ." (" ;
$i = 0;
// set up the columns for the insert statement
foreach ($fields as $field => $value) {
$i++;
$sql .= $field;
if ($countfields != $i ) {
$sql .= ", ";
}
}
// close the column statement, open the value statement, since this is prepared, we will add question marks and add later the values
$sql .= ") ";
$sql .= "VALUES (";
$i = 0;
$parameters = "";
$notation = "";
foreach ($fields as $field => $value) {
$i++;
$sql .= "?";
// set up the notation in the bind parameters
switch($value['notation']) {
case "int":
$notation .= "i";
break;
case "string":
$notation .= "s" ;
break;
}
// need to escape the email and username values
$parameters .= "'".$value['value']."'" ;
if ($countfields != $i ) {
$sql .= ", ";
$parameters .= ", ";
}
}
$sql .= ")";
$stmt = mysqli_prepare($con, $sql);
mysqli_stmt_bind_param($stmt, $notation, $parameters);
if(mysqli_stmt_execute($stmt)) {
echo "data entered";
} else {
echo "error in following query:". $sql;
}
}
}
break;
This works all fine except for 1 tiny thing and that is when I enter more than 1 item in the database. It gives me the following error
mysqli_stmt_bind_param(): Number of elements in type definition string
doesn't match number of bind variables in .... line 647
I realized after a while that it is the parameter variable that is the case. The bind parameter here is only 1 variable in which I separate it all nicely with a comma (in order to mimic the list). Viewing this optical would say this looks fine, however I think the bind parameter statement really requires separate variables. At this point it sees actually just one variable, rather than the 4 in my test case.
I tried looping it this way:
mysqli_stmt_bind_param($stmt, $notation,
foreach ($fields as $field => $value) {
echo $value['value'];
if ($countfields != $i ) {
echo ",";
}
}
);
But to no avail, since it will spit out the following.
Parse error: syntax error, unexpected 'foreach' (T_FOREACH) in
Does anybody have an idea how to solve this issue?
== edit ==
table structure as requested, although I doubt it is that problem, since I get a bind parameter error, not an error in executing the statement.
== edit 2 ==
also tried the following, which didn't help, since it didn't stack (I saw this in PDO)
foreach ($fields as $field => $value) {
switch($value['notation']) {
case "int":
$notation = "i";
break;
case "string":
$notation = "s" ;
break;
}
mysqli_stmt_bind_param($stmt, $notation, $value['value']);
}
You need to pass each variable individually to mysqli_stmt_bind_param, so $parameters needs to be an array, not a string. Change the following lines of code:
$parameters = "";
to:
$parameters = array();
and
$parameters .= "'".$value['value']."'" ;
to:
$parameters[] = $value['value'];
(note there is no need to escape values when you are using prepared statements)
remove this line:
$parameters .= ", ";
and finally, change
mysqli_stmt_bind_param($stmt, $notation, $parameters);
to:
mysqli_stmt_bind_param($stmt, $notation, ...$parameters);
and it should work fine.
Related
I have dynamic where conditions. They consist of the following array:
array:2 [
"brand_name" => array:2 [
0 => "a"
1 => "b"
]
"category_type" => array:1 [
0 => "AA"
]
]
I need to apply where conditions to my query.
$em = $this->getEntityManager();
$sql = " select * from products as p";
$i = 0;
foreach ($wheres as $key => $value) {
if ($i === 0) {
$sql .= " WHERE";
} else {
$sql .= " AND";
}
$sql.= " te.$key IN (:$key)";
$i +=1;
}
I am not sure how to assign the value to the query. If I had single where condition, I did something like this:
$params = array(
$ids,
);
$query = $em->getConnection()->executeQuery(
$sql,
$params,
array(
\Doctrine\DBAL\Connection::PARAM_STR_ARRAY,
\PDO::PARAM_INT,
)
);
$records = $query->fetchAll();
But I don't know how to fix where where conditions are in dynamic.
This is very easy using the query builder. It's the kind of thing it was designed for.
Something like this would take you there:
$qb = $this->createQueryBuilder('p');
$suffix = 0;
foreach ($conditions as $key => $value) {
$parameter = 'query_' . $suffix++;
$qb->andWhere("p.$key IN :$parameter")
->setParamter($parameter, $value);
}
$records = $qb->getQuery()->getResult()
You'll need to make adjustments to suit your data model. In your question you are selecting products as p, but then you are trying to select from te, so I guess some pieces are missing from the puzzle.
But you should be able to finish it from here.
I am using SQLite3 and PHP, and try to write a generic function to execute my queries.
For this I would like to retrieve the name of the parameters from variables in the bindParam.
But it doesn't seem to work. Here is a code showing the unexpected behavior:
<?php
header("Content-Type: text/plain");
$db = new SQLite3(':memory:');
$db->exec("create table mytable (lsid integer primary key autoincrement, usid TEXT, source TEXT)");
$myid = 'agoodid';
$mydatasources = array('home', 'news');
foreach($mydatasources as $datasource) {
$params[] = array(':datasource' => $datasource, ':usid' => $myid);
}
echo "here are the inputs : " .PHP_EOL;
print_r($params);
$querystring = 'insert into mytable (source, usid) values (:datasource, :usid)' ;
echo " I prepare the query '$querystring'" . PHP_EOL;
$query = $db->prepare($querystring);
foreach($params as $set) {
foreach($set as $key => $value) {
echo " Setting $key = $value." . PHP_EOL;
$query->bindParam($key, $value, SQLITE3_TEXT);
}
echo " I execute the query" . PHP_EOL;
$queryres[] = $query->execute();
$query->reset();
}
$results = $db->query('select * from mytable');
echo "and here is what I get : " . PHP_EOL;
while ($row = $results->fetchArray(SQLITE3_ASSOC)) {
print_r($row);
}
?>
And here is the final result :
Array
(
[lsid] => 1
[usid] => agoodid
[source] => agoodid
)
Array
(
[lsid] => 2
[usid] => agoodid
[source] => agoodid
)
All the parameters seem to be bound with the value of the last bound parameter.
The expected result is:
Array
(
[lsid] => 1
[usid] => agoodid
[source] => home
)
Array
(
[lsid] => 2
[usid] => agoodid
[source] => news
)
How to do this? As a reminder: the aim is to not hard code the name of the parameter in bindParam.
I got the binParam function wholy wrong. it is attaching to the given parameter in the sql query a reference to the given variable in php.
I have to use bindValue instead.
I'm trying to be able to add parameters to to my prepared statement, query and arrays look right. But the "Number of elements in type definition string doesn't match number of bind variables" error is triggered.
$sql = 'SELECT * FROM `feed` ';
$types = array();
$params = array();
if( isset($_GET['p']) ) {
$page = $_GET['p'];
}
else {
$page = 0;
}
if( isset($_GET['q']) ) {
$sql .= 'WHERE `title` LIKE ? ';
$search = $_GET['q'];
array_push($types, 's');
array_push($params, $search);
}
$sql .= 'ORDER BY `time` DESC LIMIT ?, 6';
array_push($types, 'i');
array_push($params, $page);
$stmt = $mysqli->prepare($sql);
$params = array_merge($types, $params);
$refs = array();
foreach($params as $key => $value)
$refs[$key] = &$params[$key];
call_user_func_array(array($stmt, 'bind_param'), $refs);
(Printed from the server)
Query: SELECT * FROM feed WHERE title LIKE ? ORDER BY time DESC LIMIT ?, 6
Array merge:
Array
(
[0] => s
[1] => i
[2] => word
[3] => 0
)
Thanks.
My understanding is that the first parameter 'types' is a string of the types of the parameters, not an array. so the the parameter list for the example should look like:
Array
(
[0] => si
[1] => word
[2] => 0
)
This is untested code: but implode should do what we want from the '$types' array
$strTypes = implode('', $types);
i will check it later.
I have a check box which takes some values and the below one is the post value which I get from my matrix form. Now the array value which I have below should be formated as like this
Post values:
Array (
[31_1] => on
[31_2] => on
[31_3] => on
[56_2] => on
[56_4] => on
[66_1] => on
[66_3] => on
)
Expected value:
31=>1,2,3
56=>2,4
66=>1,3
I will be happy if I am able to store the values in a database table (author_book) like this:
S.No Author_ID Book_IDs
1 31 1,2,3
2 56 2,4
3 66 1,3
In short, the post values should be stored in DB tables for me to proceed further. How can I achieve this?
This code would construct the queries for you, remember to use some data injection prevention mechanism
<?php
$x = array (
"31_1" => "on",
"31_2" => "on",
"31_3" => "on",
"56_2" => "on",
"56_4" => "on",
"66_1" => "on",
"66_3" => "on"
);
$newarray = array();
foreach($x as $key => $val){
$key = explode("_", $key);
$newkey = $key[0];
$newval = $key[1];
$newarray[$newkey][] = $newval;
}
foreach($newarray as $key => $val){
$query = "INSERT INTO (Author_ID, Book_IDs) VALUES (" . $key . ",'" . join(',', $val) . "')";
echo $query . "<br />";
}
foreach($array_name as $key=> $value)
{
$var1=$key;
$var2=$value;
// here you can have your db statements to insert the values
}
Here you go. There might be a shorter way of doing it too:
<?php
$array = array (
'31_1' => 'on',
'31_2' => 'on',
'31_3' => 'on',
'56_2' => 'on',
'56_4' => 'on',
'66_1' => 'on',
'66_3' => 'on',
);
$new_array = array();
foreach($array as $ind=>$val){
//breaks string at '_' and gets 31 and 1 separately
$key_val = explode('_',$ind);
if(array_key_exists($key_val[0],$new_array)){
//this is to append if key exists, eg. 31 => 1,2,3
$new_array[$key_val[0]] = $new_array[$key_val[0]].",".$key_val[1];
}
else
{
$val = $key_val[1];
$new_array[$key_val[0]] = $val;
}
}
print_r($new_array);
?>
Fiddle
I believe you only wanted to insert values for author_id whose is set to ON
unset all the index set to OFF
Try something similar:
$books=array();
foreach($array_name as $key=> $value){
if($value==='on'){
//prepare the array
list($author_id,$books[$author_id][])=explode("_",$key)
}
}
foreach($temp as $k=>$v){
$q->query("INSERT INTO author_book(author_id,books_id) VALUES($k,".implode(',',$v)));
}
Thanks
and keep asking questions :)
I am passing an array to a query. However, I can't seem to add each value `.
The array Im passing is:
Array (
[name] => Name
[address_1] => Address 1
[address_2] => Address 2
[address_3] => Address 3
[address_4] => Address 4
[post_code] => Post COde
[proptype] => rent
[style] => house
[beds] => 1
[bathrooms] => 1
[garden] => 1
[furnished] => yes
[deposit] => Deposit
[available] => 10/18/2013
[description] => Description
)
Below is my code:
foreach ($data as $column => $value) {
$columns .= ($columns == "") ? "" : ", ";
$columns .= $column;
$values .= ($values == "") ? "" : ", ";
$values .= $value;
}
$sql = "INSERT INTO $table ($columns) VALUES ($values)";
echo "--->" . $sql;
exit;
I know I need to enclose each value but I can't see where I need to do this.
Thanks for your time.
Try:
foreach ($data as $column => $value) {
$columns .= ($columns == "") ? "" : ", ";
$columns .= $column;
$values .= ($values == "") ? "" : ", ";
$values .= "'" . $value . "'";
}
You could also to use a few built-in php functions:
// join column names with a comma
$columns = join(array_keys($data),',');
// pass every value through mysql-escape and join the values with quotes and commas
$values = join(array_map("mysql_real_escape_string",array_values($data)),'","');
// use the produced strings; make sure you wrap the values string with double quotes
$sql = "INSERT INTO $table ($columns) VALUES (\"$values\")";
For reference:
array_keys,
array_values,
array_map, mysql_real_escape_string, join
I am using mysql_real_escape_string for security reasons.