Binding array of values in prepared statement PDO PHP - php

I'm trying to bind my values into a prepared statement in PDO.
Here is the pre requisite codes that that uses the prepared statement block:
$tab = 'air_user';
$fie = array('USER_NAME', 'USER_PASSWORD' , 'USER_EMAIL');
$name = $_POST['name'];
$pass = $_POST['password'];
$email = $_POST['email'];
$val = array(
'name' => $name,
'pass' => $pass,
'email' => $email
);
$this->connect($tab,$fie,$val);
And here is the part wherein I prepare those values and make the necessaru insertions:
public function connect($table,$fields,$values)
{
try{
$con = new PDO ('mysql:host=localhost;dbname=air','root','123456');
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$con->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$fields = implode(", ", $fields);
echo $fields;
$values = implode(", ", $values);
echo $values;
// have to make this prevent sql injection //
$stmt = $con->prepare("INSERT INTO $table(ID,$fields) VALUES (?,?,?,?)");
$stmt->execute(array('',$values));
} catch(PDOException $e) {
die("this cant connect the database");
}
}
so why isit my INSERT not Working ? isit can anyone help me take a look of it , i tryed so many things , none of them work.

No, don't implode the values that your going to pass inside the ->execute(), it must be an array:
$fields = implode(", ", $fields);
// $values = implode(", ", $values); // DONT IMPLODE!
$values = array_values($values);
$stmt = $con->prepare("INSERT INTO $table(ID,$fields) VALUES (NULL, ?,?,?)");
$stmt->execute($values);
Or #Augwa's suggestion:
// $fields = implode(", ", $fields); // not needed
// $values = implode(", ", $values); // DONT IMPLODE!
$placeholders = substr(str_repeat('?,', sizeOf($fields)), 0, -1);
// $placeholders = implode(', ', array_fill(0, count($values), '?'));
$stmt = $con->prepare(
sprintf(
"INSERT INTO %s (%s) VALUES (%s)",
$table,
implode(',', $fields),
$placeholders
)
);
$stmt->execute($values);

Related

How to insert an array into SQL using PHP?

I have an array like:
$arrays = array(
array('id' => '1','Name' => 'Monica','online' => '1'),
array('id' => '2','Name' => 'Jessica','online' => '1')
);
I only included 2, but let's say I have 200 of these. I already have a table in SQL with associated columns id, name and online.
Can you help me input these into database? I'm developing using wordpress. From Insert array into MySQL database with PHP I have an idea of how to do it for 1 single array
If you're having an array , you need to use a foreach loop to know the length content of insertion.
This is an example of insertion:
if(is_array($array)){
$sql = "INSERT INTO some_table (id, name, online) values ";
$valuesArr = array();
foreach($array as $row){
$id= (int) $row['id'];
$email = mysql_real_escape_string( $row['name'] );
$name = mysql_real_escape_string( $row['online'] );
$valuesArr[] = "('$id', '$email', '$name')";
}
$sql .= implode(',', $valuesArr);
mysql_query($sql) or exit(mysql_error());
}
Please try this.
Using PDO example
$sql = <<<EOT
INSERT IGNORE INTO
table_name (id, name, online)
VALUES
(:id, :name, :online)
;
EOT;
define("INSERT_UPDATE_SQL", $sql,true);
try{
$con = new PDO(CONNECTION_STRING);
if(is_array($arrays)){
$stmt = $con->prepare(INSERT_UPDATE_SQL);
$stmt->bindParam(':id', $id);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':online', $online);
foreach($arrays as $row){
$id = (int)$row['id'];
$name = $row['Name'];
$online = $row['online'];
$stmt->execute();
}
$stmt = null;
}
$con = null;
}catch (PDOException $e) {
echo 'error !!';
throw $e;
}
not changed if already registered.

PDO multi insert statement

I've got a working insert for a single input field but when I try to add a couple more it seems to break everything. I have a database connection working fine and including that correctly at the top of the page when I change the "isset" to have the 3 columns it breaks.
This is my set statement;
if(isset($_POST['title, question, tags']))
{
$success = insertData('questions', 'title', $_POST['title']);
$success = insertData('questions', 'question', $_POST['question']);
$success = insertData('questions', 'tags', $_POST['tags']);
if(!$success)
echo 'Sorry failed :(';
}
The function I call from a functions php file;
function insertData($tablename, $columnName, $value)
{
$sql = 'INSERT into '.$tablename.'('.$columnName.') VALUES(:Value)';
$mysqlConnection = getConnection();
$statement = $mysqlConnection->prepare($sql);
$statement->bindValue(":Value", $value, PDO::PARAM_STR);
$bReturn = false;
try
{
$statement->execute();
$bReturn = true;
}
catch(PDOExecption $e)
{
echo $e->getMessage();
}
return $bReturn;
}
Does anyone know where I'm going wrong here?
if(isset($_POST['title, question, tags']))
Is not correct syntax
instead You can do:
if(isset($_POST['title']) && isset($_POST['question']) && isset($_POST['tags']))
or even
if(isset($_POST['title'], $_POST['question'], $_POST['tags']))
It would be easier to do execute it without binding:
insertData
function insertData($tablename, $params){
//build query string
$column_string = implode(',', array_keys($params));
$value_string = implode(',', array_fill(0, count($params), '?'));
$sql_string = "INSERT INTO {$tablename} ({$columnString}) VALUES ({$value_string})";
//prepare query
$mysqlConnection = getConnection();
$statement = $mysqlConnection->prepare($sql_string);
//execute query
$success = $statement->execute(array_values($params));
//return boolean success
return $success;
}
But If you really need to bind, you can do it the following way:
function insertDataBind($tablename, $params){
//build query string
$column_string = implode(',', array_keys($params));
$value_string = implode(',:', array_keys($params));
$sql_string = "INSERT INTO {$tablename} ({$column_string}) VALUES (:{$value_string})";
//prepare query
$mysqlConnection = getConnection();
$statement = $mysqlConnection->prepare($sql);
//bind
foreach($params as $key=>$value){
$statement->bindValue($key, $value);
}
//execute query
$success = $statement->execute();
//return boolean success
return $success;
}
usage:
if(isset($_POST['title'], $_POST['question'], $_POST['tags'])){
$params = array('title' => $_POST['title'],
'question'=>$_POST['question'],
'tags'=>$_POST['tags']
);
$success = insertData('questions', $params);
if(!$success)
echo 'Sorry failed :(';
}

PHP/MySQL INSERT same data INTO two Tables

I have two forms that share some same columns: NAME, EMAIL, NOMINEE, DEPT, RANK and TIMESTAMP
and I want to store those same columns in a new table called: TEACHING_AWARD_ALL_NOMINATIONS.
I have came up with the code to store each data into different table and then there should be some code to store the shared columns into TEACHING_AWARD_ALL_NOMINATIONS table.
I haven't came up with the code yet, please help!!!!
$srr = array_map('mysql_escape_string', $_REQUEST);
if ($srr['NOMINATIONTYPE'] == 'STUDENT')
$fields = Array('NAME', 'EMAIL', 'NOMINEE', 'DEPT', 'COURSE', 'YEARTERM', 'REQUIRED_FOR_MAJOR', 'MAJOR_LEARNING_OBJECTIVES', 'WHAT_EXTENT_INSTRUCTOR_HELP', 'RANK', 'RANK_COMMENT', 'TEXTBOX_1', 'TEXTBOX_2', 'TEXTBOX_3', 'TEXTBOX_4', 'TEXTBOX_5');
else if ($srr['NOMINATIONTYPE'] == 'FACULTY')
$fields = Array('NAME', 'EMAIL', 'NOMINEE', 'DEPT', 'RANK', 'TEXTBOX_1', 'TEXTBOX_2', 'TEXTBOX_3');
else die('error: no nomination type');
foreach ($fields as $f)
$$f = $srr[$f];
$qry = "INSERT INTO TEACHING_AWARD_".$srr['NOMINATIONTYPE']."_NOMINATIONS (";
foreach ($fields as $f) $qry .= $f . ", ";
$qry = substr($qry, 0, -2);
$qry .= ") VALUES (";
foreach ($fields as $f) $qry .= "'" . $$f . "', ";
$qry = substr($qry, 0, -2);
$qry .= ")";
$result = mysql_query($qry) or die('An error ocurred: '.mysql_error());
echo 'Success! Thank you for submitting your nomination.';
WARNING! As noted in comments your original code is using deprecated functions and suffers from potential security issues.
Check out the refactored solution that is using PDO, and yes you
should use PDO too (instead of your current approach).
Check out the code below, untested but should do your job. As written above it uses PDO - check the docs here
// obviously, first set your connection parameters $DbHost, $DbName etc.
//connect to mysql
$dbh = new PDO("mysql:host=".$DbHost.";dbname=".$DbName, $DbUser, $DbPass, array(PDO::ATTR_PERSISTENT => true));
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->query('SET NAMES UTF8'); //assuming you use utf-8 encoding
//provide values array
$values = $YourValuesArray;
//set field types
$fields = array();
$fieldsStudent = Array('NAME', 'EMAIL', 'NOMINEE', 'DEPT', 'COURSE', 'YEARTERM', 'REQUIRED_FOR_MAJOR', 'MAJOR_LEARNING_OBJECTIVES', 'WHAT_EXTENT_INSTRUCTOR_HELP', 'RANK', 'RANK_COMMENT', 'TEXTBOX_1', 'TEXTBOX_2', 'TEXTBOX_3', 'TEXTBOX_4', 'TEXTBOX_5');
$fieldsFaculty = Array('NAME', 'EMAIL', 'NOMINEE', 'DEPT', 'RANK', 'TEXTBOX_1', 'TEXTBOX_2', 'TEXTBOX_3');
$fieldsAll = array_intersect($fieldsStudent, $fieldsFaculty);
//pick the proper field set or die
$fields = ($srr['NOMINATIONTYPE'] == 'STUDENT') ? $fieldsStudent : $fieldsFaculty;
if(empty($fields)) die('error: no nomination type');
//set tables
$table = 'TEACHING_AWARD_'.$srr['NOMINATIONTYPE'].'_NOMINATIONS';
$tableAll = 'TEACHING_AWARD_ALL_NOMINATIONS';
//construct fields string
$strFields = implode(",", $fields);
$strFieldsAll = implode(",", $fieldsAll);
//construct the placeholders string
$strIns = implode(",", array_map(function($item){ return ":".$item; }, $fields));
$strInsAll = implode(",", array_map(function($item){ return ":".$item; }, $fieldsAll));
//insert specific data
$sql = "INSERT INTO $table ($strFields) VALUES ($strIns)";
$sth = $dbh->prepare($sql);
//bind values to placeholders
foreach ($fields as $f)
{
$sth->bindValue(':' . $f, $values[$f]);
}
$sth->execute();
//insert all data
$sql = "INSERT INTO $tableAll ($strFieldsAll) VALUES ($strInsAll)";
$sth = $dbh->prepare($sql);
//bind values to placeholders
foreach ($fieldsAll as $f)
{
$sth->bindValue(':' . $f, $values[$f]);
}
$sth->execute();
EDIT:
As per your comment, to select a UNIONed set of results using PDO you can use the below (untested) code:
//connect to mysql
$dbh = new PDO("mysql:host=".$DbHost.";dbname=".$DbName, $DbUser, $DbPass, array(PDO::ATTR_PERSISTENT => true));
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->query('SET NAMES UTF8'); //assuming you use utf-8 encoding
$sql = "SELECT NAME, EMAIL, NOMINEE, DEPT, RANK, TIMESTAMP, 'STUDENT' AS TYPE FROM TEACHING_AWARD_STUDENT_NOMINATIONS
UNION
SELECT NAME, EMAIL, NOMINEE, DEPT, RANK, TIMESTAMP, 'FACULTY' AS TYPE FROM TEACHING_AWARD_FACULTY_NOMINATIONS";
$sth = $dbh->prepare($sql);
$sth->execute();
//init result array
$results = array();
//fetch the results into an array
while($row = $sth->fetch(PDO::FETCH_ASSOC))
$results[] = $row;
//show results or do whatever else you need
print_r($results);
You could try making two arrays, one for the "shared" columns (NAME, EMAIL, etc.) and another for the "type-specific" columns (COURSE, YEARTERM, etc.). Then, when you are building up your SQL statement, do a foreach on the "shared" columns followed immediately by the "type-specific" columns to simulate the entire table. It might look something like this:
$qry = "INSERT INTO TEACHING_AWARD_".$srr['NOMINATIONTYPE']."_NOMINATIONS (";
foreach ($fields_shared as $f) $qry .= $f . ", ";
foreach ($fields_typespecific as $f) $qry .= $f . ", ";
$qry = substr($qry, 0, -2);
$qry .= ") VALUES (";
foreach ($fields_shared as $f) $qry .= "'" . $$f . "', ";
foreach ($fields_typespecific as $f) $qry .= "'" . $$f . "', ";
$qry = substr($qry, 0, -2);
$qry .= ")";
I would also agree with th3falc0n's comment about looking into preparing your SQL statements with more robust tools.
Another consideration: rather than enter redundant data into a TEACHING_AWARD_ALL_NOMINATIONS table, why not simply make that a view that pulls all shared columns from each type-specific table (likely using a UNION statement)? This prevents redundant data and would make data maintenance easier (e.g. when a nomination is deleted from one of the type-specific table, it automatically vanishes from the ALL_NOMINATIONS view, etc.).

How to insert multiple rows in a mysql database at once with prepared statements?

I am trying to use staticsanĀ“s answer in this question for prepared statements.
Lets take this example:
$stmt = $mysqli->prepare("INSERT INTO something (userid, time, title) VALUES (?, ?, ?)");
$stmt->bind_param('iis', $userid, time(), $title);
$stmt->execute();
In staticsanĀ“s answer imploding the array is adding all the values into the mysql statement so that in the end we can insert multiple data into the database with just one statement.
How would this be done in my example?
This is completely valid:
$stmt = $mysqli->prepare("INSERT INTO something (userid, time, title) VALUES (?, ?, ?)");
$stmt->bind_param('iis', $userid, time(), $title);
$stmt->execute();
$stmt->bind_param('iis', $userid, time(), $title);
$stmt->execute();
$stmt->bind_param('iis', $userid, time(), $title);
$stmt->execute();
$stmt->bind_param('iis', $userid, time(), $title);
$stmt->execute();
You can foreach over your array of values to insert and bind and execute each time. It wont be quite as fast as the bulk insert in the example you linked, but it will be more secure.
You can build prepared statement using code as mentioned here,
PDO Prepared Inserts multiple rows in single query
PHP logic will be sort of like,
/**
* Insert With Ignore duplicates in Mysql DB.
*/
public static function insertWithIgnore($em, $container, $tableName, $fields, $rows)
{
$query = "INSERT IGNORE INTO $tableName (`" . implode('`,`', $fields) . "`) VALUES ";
$placeHolr = array_fill(0, count($fields), "?");
$qPart = array_fill(0, count($rows), "(" . implode(',', $placeHolr) . ")");
$query .= implode(",", $qPart);
$pdo = self::getPDOFromEm($em, $container);
$stmt = $pdo->prepare($query);
$i = 1;
foreach ($rows as $row) {
$row['created_at'] = date("Y-m-d H:i:s");
foreach ($fields as $f) {
if (!isset($row[$f])) {
$row[$f] = null;
}
$stmt->bindValue($i++, $row[$f]);
}
}
$result = $stmt->execute();
if ($result == false) {
$str = print_r($stmt->errorInfo(), true);
throw new \Exception($str);
}
$stmt->closeCursor();
$pdo = null;
}
/**
* Replace old rows in Mysql DB.
*/
public static function replace($em, $container, $tableName, $fields, $rows, $extraFieldValues = null)
{
if ($extraFieldValues != null) {
$fields = array_unique(array_merge($fields, array_keys($extraFieldValues)));
}
$query = "REPLACE INTO $tableName (`" . implode('`,`', $fields) . "`) VALUES ";
$placeHolr = array_fill(0, count($fields), "?");
$qPart = array_fill(0, count($rows), "(" . implode(',', $placeHolr) . ")");
$query .= implode(",", $qPart);
$pdo = self::getPDOFromEm($em, $container);
$stmt = $pdo->prepare($query);
$i = 1;
foreach ($rows as $row) {
if ($extraFieldValues != null) {
$row = array_merge($row, $extraFieldValues);
}
foreach ($fields as $f) {
$stmt->bindValue($i++, $row[$f]);
}
}
$stmt->execute();
if (!$stmt) {
throw new \Exception("PDO::errorInfo():" . print_r($stmt->errorInfo(), true));
}
$stmt->closeCursor();
$pdo = null;
}

Prepare MySQL statement with IN() function

Now I do:
$params = array(1,2,3);
$sql = 'select * from foo where bar in (%s)';
$sql = sprintf($sql,
implode(',', $params)
);
$params is supplied by a user so it's obviously unsafe.
How can I fix this? I would prefer using a framework like Zend.
You could use prepared statements with PDO:
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
$params = array(1,2,3);
$values = implode(',', array_fill(0, count($params), '?')); // ?,?,?
$sql = "select * from foo where bar in ($values)";
$stmt = $dbh->prepare( $sql );
$stmt->execute( $params );
By using prepared statements, you avoid the need to escape your data. You will still need to validate it though.
You have to make each array entry safe. Either using mysql_real_escape_string(), or in your case, just by casting to int. The most generic method would be the following:
function quoteString( $string ) {
return "'" . mysql_real_escape_string($string) . "'";
}
$quotedParams = array_map("quoteString", $params);
$sql = sprintf($sql,
implode(',', $quotedParams)
);
In your case, you could cast to int, so you could do it like this:
$intParams = array_map("intval", $params);
$sql = sprintf($sql,
implode(',', $intParams)
);

Categories