I have list of data in CSV and need to insert this data into a MySQL database. These data should be safely inserted i.e sanitation. So, I have used PDO object to rectify SQL injection. But, it fails to get data from CSV file and inserts null values.
Here is the example,
<?php
$servername = "localhost";
$username = "root";
$password = "";
try {
$conn = new PDO("mysql:host=$servername;dbname=contact_list",$username,$password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "connection successfully";
}
catch(PDOException $e)
{
echo "connection Failed:" . $e -> getMessage();
}
// Create CSV to Array function
function csvToArray($filename = '', $delimiter = ',')
{
if (!file_exists($filename) || !is_readable($filename)) {
return false;
}
$header = NULL;
$result = array();
if (($handle = fopen($filename, 'r')) !== FALSE) {
while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
if (!$header)
$header = $row;
else
$result[] = array_combine($header, $row);
}
fclose($handle);
}
return $result;
}
// Insert data into database
$all_data = csvToArray('contact.csv');
foreach ($all_data as $data) {
$data = array_map(function($row){
return filter_var($row, FILTER_SANITIZE_STRING, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
}, $data);
$sql = $conn->prepare("INSERT INTO contact
(title, first_name,last_name,company_name,date_of_birth,notes)
VALUES (:t, :fname, :lname,:cname,:dob,:note)");
$sql->bindParam(':t', $data[1], PDO::PARAM_STR);
$sql->bindParam(':fname', $data[2], PDO::PARAM_STR);
$sql->bindParam(':lname', $data[3], PDO::PARAM_STR);
$sql->bindParam(':cname', $data[0], PDO::PARAM_STR);
$sql->bindParam(':dob', $data[4], PDO::PARAM_STR);
$sql->bindParam(':note', $data[15], PDO::PARAM_STR);
print_r($data);
$sql->execute();
}
?>
Can anyone help me to solve this?
If you take a look at the documentation for array_combine() you'll see that its purpose is to build an associative array. You use this function in csvToArray() but later in your code you are trying to get data using numeric keys. I wouldn't expect you'd ever have anything inserted.
On a side note, you are completely defeating the purpose of prepared statements by repeatedly preparing the same statement over and over again. Prepare once and execute many times. Individually binding parameters is rarely needed, in almost all cases you can provide the data to PDOStatement::execute() as an array. It's also bad form to store HTML entities in a database; if you need to output to HTML, you perform escaping at that point.
Something like this should work (adjust array key names as necessary.)
$all_data = csvToArray('contact.csv');
$sql = $conn->prepare("INSERT INTO contact
(title, first_name, last_name, company_name, date_of_birth, notes)
VALUES (:t, :fname, :lname,:cname,:dob,:note)");
foreach ($all_data as $data) {
$params = [
":t" => $data["t"],
":fname" => $data["fname"],
":lname" => $data["lname"],
":dob" => $data["dob"],
":note" => $data["note"],
];
$sql->execute($params);
}
Related
I have a csv file that I parse and display it by storing it in an array. I was wondering how can I validate the mail or make sure it's the right format before inserting it into mysql? And, if the mail is not validate it should display an error and not insert that row to mysql.
I know I can use that filter_var($email, FILTER_VALIDATE_EMAIL) !== false; but I am not sure how to use it in my code as it is inside an array (the value of email). Any help is appreciated.
My code:
<?php
require "database.php";
$lines = file('users.csv', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
$csv = array_map('str_getcsv', $lines);
$col_names = array_shift($csv);
$users = [];
try {
$stmt = $dbh->prepare("INSERT INTO users(name, surname, email)
VALUES(:name, :surname, :email)");
foreach($csv as $row) {
$users[] = [
$col_names[0] => ucfirst(strtolower($row[0])),
$col_names[1] => ucfirst(strtolower($row[1])),
$col_names[2] => strtolower(strtolower($row[2])), //that's the mail
];
$stmt->bindValue(':name', $col_names[0], PDO::PARAM_STR);
$stmt->bindValue(':surname', $col_names[1], PDO::PARAM_STR);
$stmt->bindValue(':email', $col_names[2], PDO::PARAM_STR);
$stmt->execute();
}
}catch(PDOException $e) {
echo "Error: " . $e->getMessage();
}
$dbh = null;
?>
You can simply check it within your loop something like below
foreach($csv as $row) {
if (filter_var(strtolower(strtolower($row[2])), FILTER_VALIDATE_EMAIL) === false) {
echo("".strtolower($row[2]))." is not a valid email address"); // You can break the loop and return from here
}
$users[] = [
$col_names[0] => ucfirst(strtolower($row[0])),
$col_names[1] => ucfirst(strtolower($row[1])),
$col_names[2] => strtolower(strtolower($row[2])), //that's the mail
];
$stmt->bindValue(':name', $col_names[0], PDO::PARAM_STR);
$stmt->bindValue(':surname', $col_names[1], PDO::PARAM_STR);
$stmt->bindValue(':email', $col_names[2], PDO::PARAM_STR);
$stmt->execute();
}
Apart from this I would suggest you to create a batch insert for this.. Never execute the insertion query in a loop
I have the following code to read a JSON and store the results in a DDBB.
The code works, but it takes more than a minute to insert just 400 records.
If I open the json, it loads pretty fast.
What I'm doing wrong?
$db = new PDO('', '', '');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if(tableExists($db, 'locations') == 1)
{
$sql=$db->prepare("DROP TABLE locations");
$sql->execute();
}
$sql ="CREATE TABLE `locations` (id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, evid INT(6) NOT NULL, place VARCHAR(150), country VARCHAR(150), reg_date TIMESTAMP)" ;
$db->exec($sql);
$json = file_get_contents('thejson.php');
$data = array();
$data = json_decode($json);
foreach ($data as $key => $object)
{
if(is_object($object))
{
$id = $object->id;
$place = $object->name;
$country = substr(strrchr($object->name, "-"), 2);
$stmt = $db->prepare("INSERT INTO `locations` (evid, place, country) VALUES (:evid, :places, :country)");
$stmt->bindValue(':evid', $id, PDO::PARAM_INT);
$stmt->bindValue(':places', $place, PDO::PARAM_STR);
$stmt->bindValue(':country', $country, PDO::PARAM_STR);
$stmt->execute();
}
}
So first 2 things i would try would be moving the prepare outside the loop, and wrapping it in a transaction:
try {
$db->beginTransaction();
$stmt = $db->prepare("INSERT INTO `locations` (evid, place, country) VALUES (:evid, :places, :country)");
foreach ($data as $key => $object)
{
if(is_object($object))
{
$id = $object->id;
$place = $object->name;
$country = substr(strrchr($object->name, "-"), 2);
$stmt->bindValue(':evid', $id, PDO::PARAM_INT);
$stmt->bindValue(':places', $place, PDO::PARAM_STR);
$stmt->bindValue(':country', $country, PDO::PARAM_STR);
$stmt->execute();
}
}
$db->commit();
} catch (Exception $e) {
$db->rollBack();
throw $e;
}
Another thing you could do is try using bindParam to bind the vars by reference - this way you only need to call bindParam once on each variable name at the start, then just overwrite the values of those variables on each iteration and call execute.
try {
$db->beginTransaction();
$stmt = $db->prepare("INSERT INTO `locations` (evid, place, country) VALUES (:evid, :places, :country)");
$id = 0;
$place = '';
$country = '';
$stmt->bindParam(':evid', $id, PDO::PARAM_INT);
$stmt->bindParam(':places', $place, PDO::PARAM_STR);
$stmt->bindParam(':country', $country, PDO::PARAM_STR);
foreach ($data as $key => $object)
{
if(is_object($object))
{
$id = $object->id;
$place = $object->name;
$country = substr(strrchr($object->name, "-"), 2);
$stmt->execute();
}
}
$db->commit();
} catch (Exception $e) {
$db->rollBack();
throw $e;
}
Similar to this instead of calling bind* you could just pass the values in via execute:
try {
$db->beginTransaction();
$stmt = $db->prepare("INSERT INTO `locations` (evid, place, country) VALUES (:evid, :places, :country)");
foreach ($data as $key => $object)
{
if(is_object($object))
{
$params = array(
':id' => $object->id,
':places' => $object->name,
':country' => substr(strrchr($object->name, "-"), 2)
);
$stmt->execute($params);
}
}
$db->commit();
} catch (Exception $e) {
$db->rollBack();
throw $e;
}
I suspect using a transaction will get you a performance gain, but I dont know that there will be a ton of difference between switching up the binding methods.
Your best bet is probably to insert all the records in a single query as #PavanJiwnani suggests:
// first we need to compile a structure of only items
// we will insert with the values properly transformed
$insertData = array_map(function ($object) {
if (is_object($object)) {
return array(
$object->id,
$object->name,
substr(strrchr($object->name, "-"), 2)
);
} else {
return false;
}
}, $data);
// filter out the FALSE values
$insertData = array_filter($insertData);
// get the number of records we have to insert
$nbRecords = count($insertData);
// $records is an array containing a (?,?,?)
// for each item we want to insert
$records = array_fill(0, $nbRecords, '(?,?,?)');
// now now use sprintf and implode to generate the SQL like:
// INSERT INTO `locations` (evid, place, country) VALUES (?,?,?),(?,?,?),(?,?,?),(?,?,?)
$sql = sprintf(
'INSERT INTO `locations` (evid, place, country) VALUES %s',
implode(',', $records)
);
$stmt = $db->prepare($sql);
// Now we need to flatten our array of insert values as that is what
// will be expected by execute()
$params = array();
foreach ($insertData as $datum) {
$params = array_merge($params, $datum);
}
// and finally we attempt to execute
$stmt->execute($params);
Try to echo timestamps with milliseconds to see what is running slow. Probably executing 400 insert queries (including opening/closing connections).
There are many factors that affects the performance of the database, please provide detailed information about the database system, PHP version and related hardware.
The bottleneck could be at:
file_get_contents('thejson.php')
if the JSON contents are fetched from a remote host, i.e. DB is running normally, network is slow.
You may also want to consider move:
$stmt = $db->prepare("INSERT INTO `locations` (evid, place, country) VALUES (:evid, :places, :country)");
out of the foreach loop.
For a PDO execution statement I am trying to make any static information such as column names and array strings to a dynamic array which contains every column from the MySQL table.
The original code was:
$stmt = $conn->prepare("INSERT into data (`username,` `password`, `email`) VALUES username = :username , password = :password , email = :email ");
$stmt->execute(array(
':username' => $entry_username,
':password' => $entry_password,
':email' => $entry_email
));
So far I have been able to change the sql statement to
$sql = "INSERT into DATA (`" . implode('`,`', $columns) . "`) values (:" . implode(',:', $columns) . ")";
$stmt = $conn->prepare($sql);
but have been unable to do a similar thing to the execution array to make it dynamically variating like the statement.
I have tried adding a for statement in the array
for ($i = 0; $i < count($columns); $i++) {
':'.$columns[$i] => ${'entry_'.$columns[$i]};
}
but this hasn't worked.
Any help would be much appreciated.
Thanks in advance!
This is a perfect situation to make good use of a prepared statement.
Try this:
I am kind of assuming what the varuables will be called in the $columns array here.
$stmt = $conn->prepare("INSERT into data
(username, password, email) VALUES( :username , :password, :email )");
$stmt->bindParam(':username', $username, PDO::PARAM_STR);
$stmt->bindParam(':password', $password, PDO::PARAM_STR);
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
foreach ( $columns as $column ) {
$username = $column['username'];
$password = $column['password'];
$email = $column['email'];
$result = $stmt->execute();
if ( ! $result ) {
// add some error checking code here
}
}
Basically, your code would look like this.
$entry = array(
'username' => $_POST['username'], //assuming it's comming from the post data or for instance $row['username'] if from previous select statement
'password' => $_POST['password'],
'email' => $_POST['email']
);
$sth = $dbh->prepare('INSERT into data (`username,` `password`, `email`) VALUES (:username, :password, :email)');
$sth->bindValue(':username', $entry['username'], PDO::PARAM_INT);
$sth->bindValue(':password', $entry['password'], PDO::PARAM_STR);
$sth->bindValue(':email', $entry['email'], PDO::PARAM_STR);
$sth->execute();
If you want the bound variables to be dynamically created, then you need to create with a loop the bindValue rows:
$entry = array(
'username' => $_POST['username'], //assuming it's comming from the post data or for instance $row['username'] if from previous select statement
'password' => $_POST['password'],
'email' => $_POST['email']
);
$sth = $dbh->prepare('INSERT into data (`username,` `password`, `email`) VALUES (:username, :password, :email)');
foreach($entry as $key => $value) {
$sth->bindValue(':'.$key, $entry[$key], PDO::PARAM_STR);
}
$sth->execute();
or inside the foreach
$sth->bindValue(':'.$key, $value, PDO::PARAM_STR);
Since your keys are (username, password, email) their keynames will be initiated to $key variable, and their values to the $value variable. in the first case it will produce:
$sth->bindValue(':username', $entry['username'], PDO::PARAM_INT);
$sth->bindValue(':password', $entry['password'], PDO::PARAM_STR);
$sth->bindValue(':email', $entry['email'], PDO::PARAM_STR);
Which will be evaluated to:
$sth->bindValue(':username', $_POST['username'], PDO::PARAM_INT);
$sth->bindValue(':password', $_POST['password'], PDO::PARAM_STR);
$sth->bindValue(':email', $_POST['email'], PDO::PARAM_STR);
In the second case it will be directly evaluated.
Have in mind it's completely unacceptable to dynamically create the column names in the query. And you have to reason to do it. However, not a full query is also hard to be read from the other developers. It's enough for you to dynamically create the bound values. You can make a method do it for you. For instance, if you column names in the query are the same way aliased, as the names of the input fields, you will have nothing more to do, but to execute the query.
Let's say you have that helper method:
Class DBConnect {
private $_driver = "mysql";
private $_dbname = "xxxx";
private $_host = "xxxx";
private $_user = "xxxx";
private $_password = "xxxx";
private $_port = 3306;
private $_dbh;
public function __construct($driver = NULL, $dbname = NULL, $host = NULL, $user = NULL, $pass = NULL, $port = NULL) {
$driver = $driver ?: $this->_driver;
$dbname = $dbname ?: $this->_dbname;
$host = $host ?: $this->_host;
$user = $user ?: $this->_user;
$pass = $pass ?: $this->_password;
$port = $port ?: $this->_port;
try {
$this->_dbh = new PDO("$driver:host=$host;port=$port;dbname=$dbname", $user, $pass);
$this->_dbh->exec("set names utf8");
} catch(PDOException $e) {
echo $e->getMessage();
}
}
public function query($sql) {
$sth = $this->_dbh->prepare($sql);
foreach ($_REQUEST as $key => $value) {
if(is_int($value)) {
$param = PDO::PARAM_INT;
} elseif(is_bool($value)) {
$param = PDO::PARAM_BOOL;
} elseif(is_null($value)) {
$param = PDO::PARAM_NULL;
} elseif(is_string($value)) {
$param = PDO::PARAM_STR;
} else {
$param = FALSE;
}
$sth->bindValue(":$key", $value, $param);
}
$sth->execute();
$result = $sth->fetchAll();
return $result;
}
}
So, lets say in another class you have a lot of queries, separated by methods:
public function getFirstQuery() {
$sql = "SELECT
col1, col2
FROM table1
WHERE col3 = :col3;";
$query = $this->_db->query($sql);
return $query;
}
public function inserSecondquery() {
$sql = "INSERT INTO
`table1`
(col1, col2)
VALUES
((SELECT
id
FROM table2
WHERE col8 = :col8), :post_field_5);";
$query = $this->_db->query($sql);
return $query;
}
Assuming you have called these queries the query() method which also fetches the data, the select one you can foreach to retrieve the data, and the insert one you can just call, to insert data. The only rule here is the post fields should be named same way, for example <input name="post_field_5" />
You can also take a look here: PDO Dynamic Query Building
OK, it seems you need to find library for active record like the ones CodeIgniter uses, or... use CodeIgniter.
From the official documentation:
http://ellislab.com/codeigniter/user-guide/database/helpers.html
$this->db->insert_string();
This function simplifies the process of writing database inserts. It
returns a correctly formatted SQL insert string. Example: $data =
array('name' => $name, 'email' => $email, 'url' => $url);
$str = $this->db->insert_string('table_name', $data);
The first parameter is the table name, the second is an associative
array with the data to be inserted. The above example produces: INSERT
INTO table_name (name, email, url) VALUES ('Rick', 'rick#example.com',
'example.com')
So, in your case, you can have something like this:
<form action="" method="post">
<input type="text" name="username" value="testUser123" />
<input type="password" name="password" value="yourPass666" />
<input type="text" name="email" value="email#example.com" />
<input type="submit" value="submit" />
</form>
<?php
//... extending CI
//... opening a method
$table = 'data';
//comming from somewhere, let's dynamically populated array but for testing purpose I will hardcode:
$columns('username', 'password', 'email');
foreach($columns as $column) {
$data[$column] = $_POST[$column]; // this will produce $data=array('username'=>$_POST['username'],password=....);
}
$str = $this->db->insert_string($table, $data);
?>
If you submit the form in the beginning, you will have:
INSERT INTO data (username, password, email) VALUES ('testUser123', 'yourPass666', 'email#example.com');
The whole active record class doc (insert chosen here)
http://ellislab.com/codeigniter/user-guide/database/active_record.html#insert
If you don't have to stick to the for loop, I would suggest a foreach, which should be easier (I know the little problems with for too).
foreach ($element in $array)
{
code execution here
}
Your array element is then stored in the $element (or as you like to name it) and you can execute the command found there.
Is this what you're looking for or did I get you wrong?
I'm trying to import CSV data into a MySQL database using the fgetcsv function.
if(isset($_POST['submit'])) {
$fname = $_FILES['sel_file']['name'];
$var = 'Invalid File';
$chk_ext = explode(".",$fname);
if(strtolower($chk_ext[1]) == "csv") {
$filename = $_FILES['sel_file']['tmp_name'];
$handle = fopen($filename, "r");
$res = mysql_query("SELECT * FROM vpireport");
$rows = mysql_num_rows($res);
if($rows>=0) {
mysql_query("DELETE FROM vpireport") or die(mysql_error());
for($i =1;($data = fgetcsv($handle, 10000, ",")) !== FALSE; $i++) {
if($i==1)
continue;
$sql = "INSERT into vpireport
(item_code,
company_id,
purchase,
purchase_value)
values
(".$data[0].",
".$data[1].",
".$data[2].",
".$data[3].")";
//echo "$sql";
mysql_query($sql) or die(mysql_error());
}
}
fclose($handle);
?>
<script language="javascript">
alert("Successfully Imported!");
</script>
<?
}
The problem is it gets stuck in between the import process and displays the following error:
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 'S',0,0)' at line 1
The file is imported only partially each time. Only between 200-300 lines out of a 10000 line file are imported.
Here is the DDL of my table:
create table vpireport (
id int not null auto_increment,
item_code int,
company_id int,
purchase double,
primary key(id),
foreign key(company_id) references users(userid)
);
I haven't been able to find the problem so far, any help appreciated. Thanks.
You probably need to escape quotes, which you could accomplish using PDO and prepared statements.
I've skipped most of your code in the example for brevity and just focused on the for loop.
<?php
// Use PDO to connect to the DB
$dsn = 'mysql:dbname=YOUR_DB;host=localhost';
$user = 'DB_USERNAME';
$password = 'DB_PASSWORD';
try {
$dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
for($i =1;($data = fgetcsv($handle, 10000, ",")) !== FALSE; $i++) {
// The query uses placeholders for data
$sql = "INSERT INTO vpireport
(item_code,company_id,purchase,purchase_value)
VALUES
(:item_code,:company_id,:purchase,:purchase_value)";
$sth = $dbh->prepare($sql);
// The data is bound to the placeholders
$sth->bindParam(':item_code', $data[0]);
$sth->bindParam(':company_id', $data[1]);
$sth->bindParam(':purchase', $data[2]);
$sth->bindParam(':purhcase_value', $data[3]);
// The row is actually inserted here
$sth->execute();
$sth->closeCursor();
}
That won't get rid of any problem characters, though, so you may want to look at some kind of data sanitization if that poses a problem.
uncomment the //echo "$sql"; and look what is the last query (with error) - it may be that the csv data contains strange characters or the query is cut off.
BTW: you can also import csv file by mysql:
http://dev.mysql.com/doc/refman/5.1/en/load-data.html
$row = 1;
if (($handle = fopen("albums.csv", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ',','"')) !== FALSE) {
if($row!=1){
$num = count($data);
$albumIndex=0;
//Insert into tbl_albums
$sqlAlbums="INSERT INTO tbl_albums(albumName) VALUES ('".$data[$albumIndex]."')";
$resultAlbums=mysql_query($sqlAlbums);
}
}
$row++;
}
}
fclose($handle);
I stupidly built my web application with mysqli. Now, I'm trying to convert my data abstraction layer to pdo, but for some reason the insert query is giving me trouble. my shortcut insert function is called from the controller, and I was hoping to keep it in the name format with the table name and column/values array as the parameters.
I commented where I think the problem is below. Please help.
function insert($table, array $columns_values) {
// connect to db
$dbh = $this->db_connect();
$i = 0;
$columns = array();
$values = array();
$params = array();
foreach($columns_values as $column => $value) {
$i++;
$param = array($i => $value);
array_push($params, $param);
array_push($columns, $column);
array_push($values, '?');
}
// turn arrays into comma separated list
$columns = implode(",", $columns);
$values = implode(",", $values);
$stmt = $dbh->prepare("INSERT INTO $table ($columns) VALUES ($values)");
foreach ($params as $param_stmt) {
// i think this is where the problem is
foreach ($param_stmt as $placeholder => $value) {
$stmt->bindParam($placeholder, $value);
}
}
$stmt->execute();
return $stmt;
} // end insert()
I wouldn't do it your way. After a few minutes, I came up with this:
/**
* Function to insert a list of values to the database.
*
* #param PDO $pdo
* #param string $table
* #param array $columns_values
*
* #throws \Exception
* #throws \PDOException
*/
function insert_to_db(PDO $pdo, $table, array $columns_values) {
//Some data validation.
if (empty($columns_values)) {
throw new \Exception("Insert at least one value.");
}
if (empty($table)) {
throw new \Exception("Table may not be empty.");
}
//Implode all of column names. Will become the columns part of the query.
$str_columns = implode(", ", array_keys($columns_values));
//Implode all column names after adding a : at the beginning.
//They will become the placeholders on the values part.
$prepared_column_names = array_map(function ($el) {
return ":$el";
}, array_keys($columns_values));
$prepared_str_columns = implode(", ", $prepared_column_names);
//The query itself. Will look like "INSERT INTO `$table` (col1, col2, col3) VALUES (:col1, :col2, :col3);"
$query = "INSERT INTO `$table` ($str_columns) VALUES ($prepared_str_columns);";
//Prepare the query
$stmt = $pdo->prepare($query);
//Iterate over the columns and values, and bind the value to the placeholder
foreach ($columns_values as $column => $value) {
$stmt->bindValue(":$column", $value);
}
//Execute the query
$stmt->execute();
}
Things I changed
I don't instantiate the PDO object inside of the function. The function needs one in order to work, so it should be one of the arguments!
I throw Exceptions in case of an error. It's a better way of handling errors.
I use named placeholders instead of unnamed ones (:name vs ?). Produces more readable, easier to follow queries, should you ever need to debug.
Added comments to code. Again, you understand what you wrote now, but will you 6 months from now?
I made use of array_keys() to automatically generate an array full of keys (i.e. the columns), instead of looping and manually adding one.
Some tips
When you instantiate a PDO object, make sure it throws PDOExceptions on error! Like so:
new PDO($dsn, $user, $pass, array(PDO::PARAM_ERRMODE => PDO::ERRMODE_EXCEPTION));
or
$pdo = new PDO($dsn, $user, $pass);
$pdo->setAttribute(PDO::PARAM_ERRMODE, PDO::ERRMODE_EXCEPTION);
That way, you don't need to explicitly check for errors each time, you use a single try catch block for the whole thing, and you're good:
try {
insert_to_db($pdo, $table, $array_of_columns_and_values);
}
catch (\Exception $e) { //Will catch all kinds of exceptions, including PDOExceptions
echo $e->getMessage();
}
You haven't checked that your prepare() actually succeeded:
$sql = "INSERT ....";
$stmt = $dbh->prepare($sql);
if (!$stmt) {
die($sql . $dbh->errorInfo());
}
Never assume a query succeeded, especially when you're building one totally dynamically as you are.
Without seeing what your original $columns_values array looks like.
Hope it helps
<?php
function insert($table, $values){
$dbh = $this->db_connect();
$fieldnames = array_keys($values[0]);
$sql = "INSERT INTO $table";
/*** set the field names ***/
$fields = '( ' . implode(' ,', $fieldnames) . ' )';
/*** set the placeholders ***/
$bound = '(:' . implode(', :', $fieldnames) . ' )';
/*** put the query together ***/
$sql .= $fields.' VALUES '.$bound;
//INSERT INTO testtable( id ,col1 ,col2 ) VALUES (:id, :col1, :col2 )
/*** prepare and execute ***/
$query = $dbh->prepare($sql);
foreach($values as $vals){
$query->execute($vals);
/* Array
(
[id] =
[col1] = someval1
[col2] = Someval21
)*/
}
}
//Multi Insert
$insert = array(array('id'=>'','col1'=>'someval1','col2'=>'Someval21'),
array('id'=>'','col1'=>'someval2','col2'=>'Someval22'),
array('id'=>'','col1'=>'someval3','col2'=>'Someval23'),
array('id'=>'','col1'=>'someval4','col2'=>'Someval24')
);
insert('testtable',$insert);
?>