I am trying to create simple PDO mysql insert query statement in most clean and efficient way.
My question is that, is there any simple function in php that could both append and prepend array values and convert it to a string like implode() function do? Or am i doing it right-(See last working code i provided)
Correct me if i am wrong, implode just adds a single string inbetween each value before converting to a string.Hope my code will clear out more what i am trying to achieve.
//key as field name value as value
$field_values=array(
"firstname"=>$fname,
"lastname"=>$lname,
"phone"=>$phone);
//field name would work fine as just a comma is appended to each array key
//i need,if there is an inline way to perform array values to start with colon and end with comma.
//this doesn't work as not comma is added inbetween
$sql="INSERT INTO student (".implode(",",array_keys($field_values).") VALUES (".implode(":",$field_values).")";
//result wrong no commas
//INSERT INTO student (firstname,lastname,phone) VALUES (:firstname:lastname:phone);
//i want this
//INSERT INTO student (firstname,lastname,phone) VALUES (:firstname,:lastname,:phone);
i can't use this too
$sql="INSERT INTO student (".implode(",",array_keys($field_values).") VALUES (?,?,?);
i am using this to bind
foreach($field_values as $field=>$value)
{
$dbh->bindValue(':'.$field,$value);
}
I know i could achieve this with just writing a string like :firstname,:lastname,:phone or may be with regex or use a foreach loop to append and prepend like this.This would work fine but its lengthy
$fv="";
foreach($field_values as $field=>$value)
{
$fv.=":".$field.",";
}
$fv=rtrim($fv, ",");
$sql="INSERT INTO student (".implode(",",$field_values).") VALUES (".$fv.")";
But what i want to know whether there is a way to do that something like the code i used above. in the scenario the array keys may change, so i am searching for a dynamic efficient way.
Help me please :)
Any help is appreciated.
Thank you in advance.
This PDO Insert function will accept an array as input.
// Insert an array with key-value pairs into a specified MySQL database table.
function pdo_insert($dbh,$table,$keyvals) {
$sql = sprintf("INSERT INTO %s ( `%s` ) %sVALUES ( :%s );",
$table,
implode("`, `", array_keys($keyvals)),
implode(", :", array_keys($keyvals))
);
$stmt = $dbh->prepare($sql);
foreach ($keyvals as $field => $value) {
$stmt->bindValue(":$field", $value, PDO::PARAM_STR);
}
$stmt->execute();
return $dbh->lastInsertId();
}
// Convert special characters to HTML safe entities.
function h($str) {
return trim(stripslashes(htmlspecialchars($str, ENT_QUOTES, 'utf-8')));
}
Example:
$dbh = new PDO($dsn);
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$keyvals = [
'id' => isset($_POST['id']) ? h( $_POST['id'] ) : null,
'title' => isset($_POST['title']) ? h( $_POST['title'] ) : null,
'description' => isset($_POST['description']) ? h( $_POST['description'] ) : null,
'created_at' => time(),
'created_by' => 1,
];
$last_ids[] = pdo_insert($dbh,'products',$keyvals);
if you dont want to use a foreach to add in the : for the column names you can try something like this
$fname = "first";
$lname = "last";
$phone = "2342344";
$field_values=array(
"firstname"=>$fname,
"lastname"=>$lname,
"phone"=>$phone
);
echo "INSERT INTO student (`:".implode("`,:`",$field_values)."`) VALUES (".$fv.")";
as you can see in the insert columns i added a `: to the being and end in the columns bracket
Related
This is my first time asking a question so sorry if I am unclear. My goal is to have an html form create an associative array ($_Session) and then have that array submitted to a MySQL database table. My $_Session array is going to get very long so I was wondering if there is a way to submit the array where the keys are the MySQL table column names and the values are inserted under the column name.
I am aware that I can code something similar to
$sql = "INSERT INTO MyGuests (firstname, lastname, email)
VALUES ('John', 'Doe', 'john#example.com')";
but my issues with that is I would have to type out each insert name and value. Could there possibly be a foreach loop to go through the array and insert everything without having to type out each individual key to the array?
Here's how you can do this using mysqli prepared statements, which will help protect you if any of the variable data comes from the internet. Note that every mysqli statement has error checking so if this isn't exactly right for your environment you should quickly see where the issue is.
$_SESSION = ["firstname" => "John", "lastname" => "Doe", "email" => "john#example.com", "age" => 24] ;
// create the query
$sql = "INSERT INTO MyGuests (" .
implode(',', array_keys($_SESSION)) .
') VALUES (' .
implode(',', array_fill(0, count($_SESSION), '?')) .
')';
echo $sql;
// prepare the query (assuming mysqli, connection $conn)
$stmt = $conn->prepare($sql) or die($conn->error);
// prepare the variable types for the bind
$types = '';
foreach ($_SESSION as $value) {
if (is_int($value)) $types .= 'i';
elseif (is_numeric($value)) $types .= 'd';
else $types .= 's';
}
// need to get the values into a numerically indexed array for the splat operator
$values = array_values($_SESSION);
$stmt->bind_param($types, ...$values) or die($conn->error);
$stmt->execute() or die($stmt->error);
Note that if the keys of the $_SESSION array are derived from user input, you still need to check that they are valid to completely protect yourself from SQL injection. The ideal way to do that would be to compare them against a list of the actual column names in MyGuests.
To do what you want we can use array_walk (or just a regular foreach loop) to process each key-val pair.
We take care to add enclosing "" around string values.
Finally, we can use the INSERT INTO ... SET structure to easily get what we want into the query (rather than INSERT INTO ... VALUES).
<?php
$_SESSION = ["firstname" => "John", "lastname" => "Doe", "email" => "john#example.com", "age" => 24] ;
// we "accumulate" the result in $arr
array_walk($_SESSION, function($v, $k) use (&$arr) {
// add quotes around strings
$val = is_numeric($v)?$v:"\"$v\"";
$arr[] = "$k = $val";
});
$list = implode(", ", $arr);
$query = "INSERT INTO MyGuests SET $list";
echo $query; //INSERT INTO MyGuests SET firstname = "John", lastname = "Doe", email = "john#example.com", age = 24
Demo Code
Word of warning: you shouldn't trust any input from the internet. At the very least, you need to ensure that every key in $_SESSION is a valid column name, and you need to make every value safe against SQL-injection.
This question already has an answer here:
Mysqli prepared statements build INSERT query dynamically from array
(1 answer)
Closed 8 months ago.
I am now having a problem inserting data in associative array with its key as fields in the table and the values to be inserted into MySql database. Here is my code.
<?php
$table = 'articles';
$data = array(
'title' => 'Header',
'content' => 'This is content',
'author' => 'James');
$keys = implode(', ', array_keys($data));
$values = implode(', ', array_values($data));
$sql = 'insert into '.$table.'('.$keys.') values ('.$values.')';
$db = new mysqli('localhost', 'root', 'root', 'blog');
$db->query($sql);
?>
With this code, I wasn't able to insert the data into the database so I try to echo the query string out and I got something like this :
insert into articles(title, content, author) values (Header, This is content, James)
However, if I use the single quote in each value like this
insert into articles(title, content, author) values ('Header', 'This is content', 'James')
I can successfully insert the data into the database.
So I don't know what's wrong here. Is it a problem with the quote sign or not because when I use the single quote, this seems to work.
So please help me find the proper solution for this...
For the query you need to enclose each value in quotes. To do that you can change your implode statement to include the quotes to around the values -
$values = "'" .implode("','", array_values($data)) . "'";
EXAMPLE-demo
You should also be checking for errors.
Replace $db->query($sql);
with
if(!$result = $db->query($sql)){
die('There was an error running the query [' . $db->error . ']');
}
else{
echo "Data inserted.";
}
So I don't know what's wrong here. Is it a problem with the quote sign or not because when I use the single quote, this seems to work.
Yes, you need to use the single quote.
You can check it out:
$values = implode(', ', array_values($data));
Into something like it:
$values = implode (',', array_map (
function ($z)
{
return ((is_numeric ($z) || (is_string ($z) ? ($z == "NOW()" ? true : false) : false) || (is_array ($z)?(($z=implode(";",$z))?false:false):false)) ? $z : "'" . utf8_decode ($z) . "'");
}, array_values ($data)));
The idea is that you make every value field quoted, I meant value field by value field in the query. For instance, in my example, the function ignores NOW() as string, and keep it up to work as SQL's timestamp. Because if you treat it as string type, the command wouldn't work properly.
Anyway, the above is ugly and insecure.
I would advice you to look for some ORM like RedBeanORM or, maybe, use the proper PHP MySQL version like MySQLi. Mainly to avoid SQL injections.
Look one ORM example:
require 'rb.php';
R::setup();
$post = R::dispense('post');
$post->text = 'Hello World';
$id = R::store($post); //Create or Update
$post = R::load('post',$id); //Retrieve
R::trash($post); //Delete
Look one PHP MySQL improved version example:
$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $code, $language, $official, $percent);
$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;
mysqli_stmt_execute($stmt);
Good luck. Good learning.
Positional place-holders:
$values = implode(', ',
array_fill(0, count($data), '?')
);
// insert into articles(title, content, author) values (?, ?, ?)
Named place-holders:
$values = implode(', ', array_map(
function($value){
return ":$value";
},
array_keys($data)
));
// insert into articles(title, content, author) values (:title, :content, :author)
Not necessarily the nicest or best code.
As about the parameter array itself, I'm not familiar with mysqli but with many DB extensions you could use $data as-is.
I have form with lot of inputs, and I'm trying to import them in database (mysql).
I want to use bind but trying to avoid writing all variables so many times. Probably I can't explain so good, so I will here is a code
if(isset($_POST['firstName']) && isset($_POST['lastName']) && isset($_POST['gender'])){
$firstName=trim($_POST['firstName']);
$lastName=trim($_POST['lastName']);
$gender=trim($_POST['gender']);
if(!empty($firstName)&& !empty($lastName)) {
$unos = $db->prepare("INSERT INTO members (firstName,lastName,gender) VALUES (?,?,?)");
$unos->bind_param('sss', $firstName, $lastName, $gender);
if($unos->execute()) {....
1.Well this is working fine , and it's not a problem, but now I want to add more inputs so I tried this
if(isset($_POST['firstName']) && isset($_POST['lastName']) && isset($_POST['gender'])){
$firstName=trim($_POST['firstName']);
$lastName=trim($_POST['lastName']);
$gender=trim($_POST['gender']);
$param=array('$firstName','$lastName','$gender');
$type='sss';
$param_list = implode(',', $param);
if(!empty($param)) {
$unos = $db->prepare("INSERT INTO members (firstName,lastName,gender) VALUES (?,?,?)");
$unos->bind_param($type,implode(',', $param));
if($unos->execute()) {....
and it's not working. I get "Number of elements in type definition string doesn't match number of bind variables"...
I don't get it, because when I echo this implode thing I get what I need.
I'm pretty newbie with PHP, so help will be so precious. :)
You can try this:
if(isset($_POST['firstName']) && isset($_POST['lastName']) && isset($_POST['gender'])){
$firstName=trim($_POST['firstName']);
$lastName=trim($_POST['lastName']);
$gender=trim($_POST['gender']);
$param=array('firstName' => 's','lastName' => 's','gender' => 's');
if(!empty($param)) {
$unos = $db->prepare("INSERT INTO members (". implode(',', array_keys($param) .") VALUES (". implode(',', array_fill(0, count($param), '?')) .")");
foreach($param as $paramName => $paramType) {
$unos->bind_param($paramType, $paramName);
}
if($unos->execute()) {....
You can pus as many parameters to $param array. Key should the name of the db column, value is its type.
You will need a variable for each question mark, but you will also need to bind each of the parameters separately. In your current situation, you bind a comma-separated list of values as a single string parameter.
What about this? I attempted to make the entire code rely on a single array of fields. If you want extra fields, you can just add them to the array and the rest of the code should respond to it. I don't have a proper test environment at hand and I typed this code by heart, so sorry for any typos. :)
// The fixes list of allowed/expected fields. Other values are ignored.
$fields = array('firstname', 'lastname', 'gender');
// Check if each value exists, and put them in an array.
$paramvalues = array();
foreach ($fields as $field) do
{
if (!isset($_POST[$field]))
die("missing field $field");
$paramvalues[] = & $_POST[$field]; // Bind_param wants a ref value, hence `&`
}
// Build a list of fields for the dynamic query.
$fieldlist = implode($fields, ',');
// And a list of placeholders.
$paramlist = implode(array_fill(0, count($fields), '?'), ',');
// And a list of types, assuming all parameters are strings.
$paramtypes = str_pad('', count($fields), 's');
// Prepare the query
$unos = $db->prepare("INSERT INTO members ($fieldlist) VALUES ($paramlist)");
// Build an array of reference values to be passed to call_user_func_array:
$paramrefvalues = array();
$paramrefvalues[] = $paramtypes
foreach ($paramvalues as $value) do
{
$paramrefvalues[] = & $value;
}
// Call bind_param using this array of by-ref parameters
call_user_func_array(array($unos, 'bind_param'), $paramrefvalues);
This code is loosely based on this article
I know that this theme is very common, but i'm stuck and can't find an error.
I created an array in PHP:
$dataarray=array("FECHAS" => date("Y-m-d"),"HORAS" => date("H:i:s"),
"RGD" => 0,"RGA" => 0,"FLU" => 0,"DD2" => 0,
"H2O" => 0,"PRES:U" => 0,"U" => 0,"V" => 0,"TS" => 0,
"T1" => 0,"T2" => 0,"H1" => 0,"H2" => 0, "HS" => 0,
"VV1" => 0,"VV2" => 0);
and i've got a table in MYSQL with the same names, but when i try to put data into it, it does nothing.
for($j=0;$j<$variable_para_base;$j++)
{
$keys;
$vars;
foreach($dataarray[$j] as $k=>$v)
{
$keys.= $k.',';
$vars.= $v.",";
}
echo $keys."<br>";
echo $vars."<br>";
mysqli_query($mysqli,'INSERT INTO ff ( .$keys.) VALUES ( .vars. ) ') or die(mysql_error());
unset($keys);
unset($vars);
}
if i do it with die option it does for only once another way my key starts to have strange values in the end of it.
Any ideas, and again sorry for maybe a repeted question. I get access to DB because it doesn't give me any error, though noow i'm doubting :(.
You have syntax promlems in your query.
INSERT INTO ff ( .$keys.) VALUES ( .vars. ) '
change it to
INSERT INTO ff ( '.$keys.') VALUES ( '.$vars.') '
Also you need to add ' to the varialbles inserted as VALUES.
like that:
$vars.= "'".$v."',";
In addition your last variable is also ending with , and it shouldn't be.
So your end result might look something like this:
<?
for($j=0;$j<$variable_para_base;$j++)
{
$keys = array();
$vars = array();
foreach($dataarray[$j] as $k=>$v)
{
$keys[] = $k;
$vars[] = $v;
}
$placeholders = array_fill(0, count($keys), '?'); //used to fill a number of '?' needed to fill later
//here we use the '?' array to be placeholders for the values
$query = "INSERT INTO ff (".implode(', ', $keys).") VALUES (".implode(', ', $placeholders).")"; //implode the arrays and separate by comma
$statement = $mysqli->prepare($query);
$types = array(str_repeat('s', count($vars))); //get the number of parameters and put the 's' to it (used for string values)
$values = array_merge($types, $vars); //merge the arrays (gets you {'s', $value})
call_user_func_array(array($statement, 'bind_param'), $values); //bind the values to the statement
$result = $statement->execute(); //execute.
if($result) {
print "Array inserted, worked like a charm.";
}
else {
print "I failed, sorry...". $mysqli->error();
}
unset($keys);
unset($vars);
}
$statement->close();
?>
This is however untested so test it good.
References you can use:
Stackoverflow question: PHP - MySQL prepared statement to INSERT an array
Stackoverflow question: Best way to INSERT many values in mysqli
Stackoverflow question: Mysqli insert command
You can not insert a array directly to mysql as mysql doesn't understand php data types. Mysql only understands SQL. So to insert this array into a mysql database you have to convert it to an sql statement. This can be done manually or by a library. The output should be an INSERT statement.
Here is a standard mysql insert statement.
INSERT INTO TABLE1(COLUMN1, COLUMN2, ....) VALUES (VALUE1, VALUE2..)
If you have a table with name fbdata with the columns which are presented in the keys of your array you can insert with this small snippet. Here is how your array is converted to this statement.
$columns = implode(", ",array_keys($insData));
$escaped_values = array_map('mysql_real_escape_string', array_values($insData));
$values = implode(", ", $escaped_values);
$sql = "INSERT INTO `fbdata`($columns) VALUES ($values)";
you have error in query try this,
mysqli_query($mysqli,'INSERT INTO ff (' .$keys. ') VALUES (' .$vars. ') ') or die(mysql_error());
I have an array like this
$a = array( 'phone' => 111111111, 'image' => "sadasdasd43eadasdad" );
When I do a var-dump I get this ->
{ ["phone"]=> int(111111111) ["image"]=> string(19) "sadasdasd43eadasdad" }
Now I am trying to add this to the DB using the IN statement -
$q = $DBH->prepare("INSERT INTO user :column_string VALUES :value_string");
$q->bindParam(':column_string',implode(',',array_keys($a)));
$q->bindParam(':value_string',implode(',',array_values($a)));
$q->execute();
The problem I am having is that implode return a string. But the 'phone' column is an integer in the database and also the array is storing it as an integer. Hence I am getting the SQL error as my final query look like this --
INSERT INTO user 'phone,image' values '111111111,sadasdasd43eadasdad';
Which is a wrong query. Is there any way around it.
My column names are dynamic based what the user wants to insert. So I cannot use the placeholders like :phone and :image as I may not always get a values for those two columns. Please let me know if there is a way around this. otherwise I will have to define multiple functions each type of update.
Thanks.
Last time I checked, it was not possible to prepare a statement where the affected columns were unknown at preparation time - but that thing seems to work - maybe your database system is more forgiving than those I am using (mainly postgres)
What is clearly wrong is the implode() statement, as each variable should be handled by it self, you also need parenthesis around the field list in the insert statement.
To insert user defined fields, I think you have to do something like this (at least that how I do it);
$fields=array_keys($a); // here you have to trust your field names!
$values=array_values($a);
$fieldlist=implode(',',$fields);
$qs=str_repeat("?,",count($fields)-1);
$sql="insert into user($fieldlist) values(${qs}?)";
$q=$DBH->prepare($sql);
$q->execute($values);
If you cannot trust the field names in $a, you have to do something like
foreach($a as $f=>$v){
if(validfield($f)){
$fields[]=$f;
$values[]=$v;
}
}
Where validfields is a function that you write that tests each fieldname and checks if it is valid (quick and dirty by making an associative array $valfields=array('name'=>1,'email'=>1, 'phone'=>1 ... and then checking for the value of $valfields[$f], or (as I would prefer) by fetching the field names from the server)
SQL query parameters can be used only where you would otherwise put a literal value.
So if you could see yourself putting a quoted string literal, date literal, or numeric literal in that position in the query, you can use a parameter.
You can't use a parameter for a column name, a table name, a lists of values, an SQL keyword, or any other expressions or syntax.
For those cases, you still have to interpolate content into the SQL string, so you have some risk of SQL injection. The way to protect against that is with whitelisting the column names, and rejecting any input that doesn't match the whitelist.
Because all other answers allow SQL injection. For user input you need to filter for allowed field names:
// change this
$fields = array('email', 'name', 'whatever');
$fieldlist = implode(',', $fields);
$values = array_values(array_intersect_key($_POST, array_flip($fields)));
$qs = str_repeat("?,",count($fields)-1) . '?';
$q = $db->prepare("INSERT INTO events ($fieldlist) values($qs)");
$q->execute($values);
I appreciated MortenSickel's answer, but I wanted to use named parameters to be on the safe side:
$keys = array_keys($a);
$sql = "INSERT INTO user (".implode(", ",$keys).") \n";
$sql .= "VALUES ( :".implode(", :",$keys).")";
$q = $this->dbConnection->prepare($sql);
return $q->execute($a);
You actually can have the :phone and :image fields bound with null values in advance. The structure of the table is fixed anyway and you probably should got that way.
But the answer to your question might look like this:
$keys = ':' . implode(', :', array_keys($array));
$values = str_repeat('?, ', count($array)-1) . '?';
$i = 1;
$q = $DBH->prepare("INSERT INTO user ($keys) VALUES ($values)");
foreach($array as $value)
$q->bindParam($i++, $value, PDO::PARAM_STR, mb_strlen($value));
I know this question has be answered a long time ago, but I found it today and have a little contribution in addition to the answer of #MortenSickel.
The class below will allow you to insert or update an associative array to your database table. For more information about MySQL PDO please visit: http://php.net/manual/en/book.pdo.php
<?php
class dbConnection
{
protected $dbConnection;
function __construct($dbSettings) {
$this->openDatabase($dbSettings);
}
function openDatabase($dbSettings) {
$dsn = 'mysql:host='.$dbSettings['host'].';dbname='.$dbSettings['name'];
$this->dbConnection = new PDO($dsn, $dbSettings['username'], $dbSettings['password']);
$this->dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
function insertArray($table, $array) {
$fields=array_keys($array);
$values=array_values($array);
$fieldlist=implode(',', $fields);
$qs=str_repeat("?,",count($fields)-1);
$sql="INSERT INTO `".$table."` (".$fieldlist.") VALUES (${qs}?)";
$q = $this->dbConnection->prepare($sql);
return $q->execute($values);
}
function updateArray($table, $id, $array) {
$fields=array_keys($array);
$values=array_values($array);
$fieldlist=implode(',', $fields);
$qs=str_repeat("?,",count($fields)-1);
$firstfield = true;
$sql = "UPDATE `".$table."` SET";
for ($i = 0; $i < count($fields); $i++) {
if(!$firstfield) {
$sql .= ", ";
}
$sql .= " ".$fields[$i]."=?";
$firstfield = false;
}
$sql .= " WHERE `id` =?";
$sth = $this->dbConnection->prepare($sql);
$values[] = $id;
return $sth->execute($values);
}
}
?>
dbConnection class usage:
<?php
$dbSettings['host'] = 'localhost';
$dbSettings['name'] = 'databasename';
$dbSettings['username'] = 'username';
$dbSettings['password'] = 'password';
$dbh = new dbConnection( $dbSettings );
$a = array( 'phone' => 111111111, 'image' => "sadasdasd43eadasdad" );
$dbh->insertArray('user', $a);
// This will asume your table has a 'id' column, id: 1 will be updated in the example below:
$dbh->updateArray('user', 1, $a);
?>
public function insert($data = [] , $table = ''){
$keys = array_keys($data);
$fields = implode(',',$keys);
$pre_fields = ':'.implode(', :',$keys);
$query = parent::prepare("INSERT INTO $table($fields) VALUES($pre_fields) ");
return $query->execute($data);
}