Insert data with associative array using PDO - php

Before you duplicate your question, I read all answers that it's has a relation with my question. I'm trying to insert data with associative array for example
<?php
$data = array(
'fname'=>'joe',
'lname'=>'sina'
);
foreach ($data as $key=>$value) {
}
?>
I want to display data like this
/*insert into tblname($key)values($value);
finally the query will appear correctly format */
insert into tblname('fname','lname') values('joe','sina');

You don't need to use foreach here. If you just prepare and bind the query, you can pass $data to the execute() and get the keys by implode() on the keys.
$data = array(
'fname'=>'joe',
'lname'=>'sina'
);
$stmt = $pdo->prepare("INSERT INTO tblname (".implode(', ', array_keys($data)).") VALUES (:".implode(', :', array_keys($data)).")");
$stmt->execute($data);
The keys in the array must match the placeholders in the query (the ones with a colon in front of it). You also had a syntax error in the query, as columns cannot be quoted by singlequotes.

Related

Mysqli prepared statement : several WHERE clauses and WHERE IN (Array) [duplicate]

This question already has answers here:
How can I bind an array of strings with a mysqli prepared statement?
(7 answers)
Closed 11 months ago.
I need to run the query below. It asks me a lot of trouble. In fact, I have several "WHERE" conditions, one that requires the decomposition of an Array.
This issue helped me but it doesn't have several conditions "WHERE" .
$array = (1,2,3,4,5,6,7,8,9,10);
$clause = implode(',', array_fill(0, count($array), '?'));
if($request = $this->getConnexion()->prepare('SELECT col1, col2 FROM table WHERE col1 IN ('.$clause.') AND col2>=?') or die(mysqli_error($this->getConnexion()))) {
// The problem starts here
call_user_func_array(array($request, 'bind_param'), $array);
$request->bind_param('i', $this->getTime());
// Until here
$request->execute();
$request->bind_result($col1, $col2);
$request->store_result();
// Following the code
}
The important thing here is that you are calling bind_param() just once, with an array containing all of the parameters you'll need to bind, so your solution will be to just add the additional WHERE clause parameter onto your $array of values to bind. The IN() clause isn't a special case requiring call_user_func_array() separated from other parameters. You call it on all of them.
Something is missing though - bind_param()'s first parameter is a string of data types. All your types are i, so you'll need to use str_repeat() to create that.
// Eventually, this array will contain the other params too
$array = (1,2,3,4,5,6,7,8,9,10);
// This creates a string of ?,?,?,?... for the IN () clause
$clause = implode(',', array_fill(0, count($array), '?'));
// Add the additional value onto the $array array
// so the last param is bound with the others.
$array[] = $this->getTime();
$types = str_repeat('i', count($array));
// The params passed to call_user_func_array() must have as references, each subsequent value. Add those in a loop, but start with the $types string
$params = array($types);
foreach ($array as $key => $value) {
$params[] = &$array[$key];
}
if($request = $this->getConnexion()->prepare('SELECT col1, col2 FROM table WHERE col1 IN ('.$clause.') AND col2>=?') or die(mysqli_error($this->getConnexion()))) {
// Then bind_param() is called on all parameters
// using the $params array which includes types and param references
call_user_func_array(array($request, 'bind_param'), $params);
// Execute & fetch.
$request->execute();
$request->bind_result($col1, $col2);
$request->store_result();
// Following the code
}

PHP PDO - Passing and imploded array to a query placeholder

First of all, I apologize if this is answered somewhere else, but I couldn't find anything.
I have problems with the following code:
function register_user ($register_data) {
global $db;
array_walk ($register_data, 'array_sanitize');
$register_data ['password'] = md5 ($register_data ['password']);
$fields = '`' . implode ('`, `', array_keys ($register_data)) . '`';
$data = '\'' . implode ('\', \'', $register_data) . '\'';
$query = $db -> prepare ("INSERT INTO `users` (:fields) VALUES (:data)");
$query -> bindParam (':fields', $fields);
$query -> bindParam (':data', $data);
$query -> execute ();
}
The problem is that this is executed correctly but the query is not ran and the row is not inserted in the database.
Now, if I just do this:
$query = $db -> prepare ("INSERT INTO `users` ($fields) VALUES ($data)");
//$query -> bindParam (':fields', $fields);
//$query -> bindParam (':data', $data);
$query -> execute ();
everything works like a charm, so I am guessing the problem is with how I am passing data to the placeholders.
Can someone please explain to me why this is not working? I'd like to understand it properly in the first place.
Thanks in advance for any help.
There are two different use cases that could be described as Passing an imploded array to a query placeholder. One is using prepared statements with IN() clause in SQL. this case is already fully covered in this answer.
Another use case is an insert helper function, like one featured in your question. I've got an article that explains how to create an SQL injection proof insert helper function for PDO_MYSQL.
Given such a function is not only adding data values to the query but also table and column names, a prepared statement won't be enough to protect from SQL injection. Hence, such a function will need a helper function of its own, to protect table and field named. Here is one for MySQL:
function escape_mysql_identifier($field){
return "`".str_replace("`", "``", $field)."`";
}
And now we can finally have a function that accepts a table name and an array with data and runs a prepared INSERT query against a database:
function prepared_insert($pdo, $table, $data) {
$keys = array_keys($data);
$keys = array_map('escape_mysql_identifier', $keys);
$fields = implode(",", $keys);
$table = escape_mysql_identifier($table);
$placeholders = str_repeat('?,', count($keys) - 1) . '?';
$sql = "INSERT INTO $table ($fields) VALUES ($placeholders)";
$pdo->prepare($sql)->execute(array_values($data));
}
that can be used like this:
prepared_insert($pdo, 'users', ['name' => $name, 'password' => $hashed_password]);
the full explanation can be found in the article linked above, but in brief, we are creating a list of column names from the input array keys and a list of comma separated placeholders for the SQL VALUES() clause. And finally we are sending the input array values into PDO's execute(). Safe, convenient and concise.

How do I convert a dynamically constructed ext/mysql query to a PDO prepared statement?

I am converting some of my code that used ext/mysql (mysql_*() functions) to PDO and prepared statements. Previously when I was dynamically constructing queries I simply passed my strings through mysql_real_escape_string() and dropped them straight into my query, but now I find I need to pass the values in as an array when I execute the query, or bind the variables before execution.
How can I convert my old code to use the new database driver?
Migrating your queries from ext/mysql to PDO prepared statements requires a new approach to a number of aspects. Here I will cover a couple of common tasks that regularly need to be performed. This by no means an exhaustive to match every possible situation, it is merely intended to demonstrate some of the techniques that can be employed when dynamically generating queries.
Before we begin, a few things to remember - if something is not work right, check this list before asking questions!
If you do not explicitly disable emulated prepares, your queries are no safer than using mysql_real_escape_string(). See this for a full explanation.
It is not possible to mix named placeholders and question-mark placeholders in a single query. Before you begin to construct your query you must decide to use one of the other, you can't switch half way through.
Placeholders in prepared statements can only be used for values, they cannot be used for object names. In other words, you cannot dynamically specify database, table, column or function names, or any SQL keyword, using a placeholder. In general if you find you need to do this, the design of your application is wrong and you need to re-examine it.
Any variables used to specify database/table/column identifiers should not come directly from user input. In other words, don't use $_POST, $_GET, $_COOKIE or any other data that comes from an external source to specify your column names. You should pre-process this data before using it to construct a dynamic query.
PDO named placeholders are specified in the query as :name. When passing the data in for execution, the corresponding array keys can optionally include the leading :, but it is not required. A placeholder name should contain only alpha-numeric characters.
Named placeholders cannot be used more than once in a query. To use the same value more than once, you must use multiple distinct names. Consider using question mark placeholders instead if you have a query with many repeated values.
When using question mark placeholders, the order of the values passed is important. It is also important to note that the placeholder positions are 1-indexed, not 0-indexed.
All the example code below assumes that a database connection has been established, and that the relevant PDO instance is stored in the variable $db.
Using an associative array as a column/value list
The simplest way to do this is with named placeholders.
With ext/mysql one would escape the values as the query was constructed and place the escaped values directly into the query. When constructing a PDO prepared statement, we use the array keys to specify placeholder names instead, so we can pass the array directly to PDOStatement::execute().
For this example we have an array of three key/value pairs, where the key represents a column name and the value represents the value of the column. We want to select all rows where any of the columns match (the data has an OR relationship).
// The array you want to use for your field list
$data = array (
'field1' => 'value1',
'field2' => 'value2',
'field3' => 'value3'
);
// A temporary array to hold the fields in an intermediate state
$whereClause = array();
// Iterate over the data and convert to individual clause elements
foreach ($data as $key => $value) {
$whereClause[] = "`$key` = :$key";
}
// Construct the query
$query = '
SELECT *
FROM `table_name`
WHERE '.implode(' OR ', $whereClause).'
';
// Prepare the query
$stmt = $db->prepare($query);
// Execute the query
$stmt->execute($data);
Using an array to construct a value list for an IN (<value list>) clause
The simplest way to achieve this is using question mark placeholders.
Here we have an array of 5 strings that we want to match a given column name against, and return all rows where the column value matches at least one of the 5 array values.
// The array of values
$data = array (
'value1',
'value2',
'value3',
'value4',
'value5'
);
// Construct an array of question marks of equal length to the value array
$placeHolders = array_fill(0, count($data), '?');
// Normalise the array so it is 1-indexed
array_unshift($data, '');
unset($data[0]);
// Construct the query
$query = '
SELECT *
FROM `table_name`
WHERE `field` IN ('.implode(', ', $placeHolders).')
';
// Prepare the query
$stmt = $db->prepare($query);
// Execute the query
$stmt->execute($data);
If you have already determined that you want to use a query with named placeholders, the technique is a little more complex, but not much. You simply need to loop over the array to convert it to an associative array and construct the named placeholders.
// The array of values
$data = array (
'value1',
'value2',
'value3',
'value4',
'value5'
);
// Temporary arrays to hold the data
$placeHolders = $valueList = array();
// Loop the array and construct the named format
for ($i = 0, $count = count($data); $i < $count; $i++) {
$placeHolders[] = ":list$i";
$valueList["list$i"] = $data[$i];
}
// Construct the query
$query = '
SELECT *
FROM `table_name`
WHERE `field` IN ('.implode(', ', $placeHolders).')
';
// Prepare the query
$stmt = $db->prepare($query);
// Execute the query
$stmt->execute($valueList);

Inserting array values into MySQL

I tried to find another question with the answer to this but I've had no luck. My question is basically...will this work?
$insert_tweets = "INSERT INTO tweets (
'id',
'created_at',
'from_user_id',
'profile_image',
'from_user',
'from_user_name',
'text'
) VALUES (
{$user_data[$i]["id"]},
{$user_data[$i]["created_at"]},
{$user_data[$i]["from_user_id"]},
{$user_data[$i]["profile_image"]},
{$user_data[$i]["from_user"]},
{$user_data[$i]["from_user_name"]},
{$user_data[$i]["text"]}
)"
for($i=0;$i<count($user_data);$i++){
mysqli_query($mysqli,$insert_tweets);
}
$user_data is a multi-dimensional array, the first level of which is numeric, the subsequent level is associative.
Also, what would be the best way to "database prepare"/sanitize the associative array variables prior to insertion? I don't anticipate any malicious data but it is always possible.
for($i=0;$i<count($user_data);$i++){
$insert_tweets = "INSERT INTO tweets ('id','created_at','from_user_id','profile_image','from_user','from_user_name','text') VALUES ({$user_data[$i]["id"]},{$user_data[$i]["created_at"]},{$user_data[$i]["from_user_id"]},{$user_data[$i]["profile_image"]},{$user_data[$i]["from_user"]},{$user_data[$i]["from_user_name"]},{$user_data[$i]["text"]})";
mysqli_query($mysqli,$insert_tweets);
}
This should work
Yes, it will work, but the best way to do this would be to use PDO.
You can create nameless parameters in your prepare statement and then just pass in a array to bind values to those params.
$data = array('val1', 'val2');
$query = $db->prepare("INSERT INTO table (col1, col2) VALUES (? , ?)");
$query->execute($data);
PDO will escape the input values for you.
Here's a tutorial on PDO to get you started
http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
Here is my suggestion on sanitizing your array:
What i do is create a basic function for sanitizing data:
function array_sanitize(&$item){
$item = mysql_real_escape_string($item);
}
Then you can use the array_walk() to sanitize your array with your new function. (php manual refrence)
and sanitize by passing in your array like this:
array_walk($user_data, 'array_sanitize');

Store array contents in database

I have a php function getContactList():
$res = getContactList(trim($_POST['username']), trim($_POST['password']));
which returns this array:
$contactList[] = array('name' => $name, 'email' =>$email);
I need to store the contents of this array into a MySQL database.
Somehow can i store the entire contents of the array in the database at one go ??
The number of array items will be more than 500 at each go , so i wanna avoid the usual looping practice and calling the "Insert" statement in the for loop as this will need a long time to execute.
Note: I need to store the results in separate columns - One for Name and another for Email. With 500 items in that array I need to have 500 rows inserted - one Name-Email pair per row.
$values = array();
// the above array stores strings such as:
// ('username', 'user#domain.com')
// ('o\'brien', 'baaz#domain.com')
// etc
foreach($contactList as $i => $contact) {
$values[] = sprintf(
"('%s', '%s')",
mysql_real_escape_string($contact['name'], $an_open_mysql_connection_identifier),
mysql_real_escape_string($contact['email'], $an_open_mysql_connection_identifier)
);
}
$query = sprintf(
"INSERT INTO that_table(name, email) VALUES %s",
implode(",", $values)
);
If you are trying to insert many rows, i.e. run the same query many times, use a prepared statement.
Using PDO, you can do this:
// prepare statement
$stmt = $dbh->prepare("INSERT INTO contacts (email, name) VALUES (:email, :name);");
// execute it a few times
foreach($contactList as $contact) {
$stmt->bindValue(':email', $contact['email'], PDO::PARAM_STR);
$stmt->bindValue(':name', $contact['name'], PDO::PARAM_STR);
$stmt->execute();
}
PDO will also take care of proper string escaping.
use the standard php serialize function
$serData_str = serialize($contactList);
then save it in the DB
after reading your data from DB simply unserialize it
$myData_arr = unserialize($serContactList);
In the loop you can create an insert statement and execute it after the loop. the insert statement will include all content.
The statement would look like
INSERT INTO employee (name) VALUES ('Arrayelement[1]'),('Arrayelement[2]'), ('Arrayelement[3]'),('Arrayelement[4]');

Categories