I’m trying to switch these mySQl INSERT INTO and Update statements to PDO prepared statements (primarily to prevent SQL Injection), but I’m having some difficulty getting the syntax right.
I’m currently using 2 types of INSERT/Update statements:
Statement 1 – Names Are Hardcoded
$qry = "INSERT INTO customer_info(fname, lname, email, user_name, password)
VALUES('$_POST[fname]','$_POST[lname]','$_POST[email]','$user_name','".sha1($salt + $_POST['password'])."')";
$result = @mysql_query($qry)
Statement 2 – Adding Names Dynamically
Instead of listing every element’s name, most names are added dynamically (names are referenced as either $fieldlist or $setlist, and values are $vallist). The only names/values which are hardcoded are user_id or those which are arrays. I’ve included the full code for this below.
$result = mysql_query('UPDATE fit_table SET '.$setlist.' WHERE user_id='.$user_id);
if (mysql_affected_rows()==0) {
$result = mysql_query('INSERT INTO fit_table ('.$fieldlist.') VALUES ('.$vallist.')'); };
This is what I’ve tried:
Statement 1 – Based on this post https://stackoverflow.com/a/60530/1056713
$stmt = $conn->prepare("INSERT INTO customer_info VALUES(:fname, :lname, :email, :user_name, :password)");
$stmt->bindValue(':fname', $fname);
$stmt->bindValue(':lname', $lname);
$stmt->bindValue(':email', $email);
$stmt->bindValue(':user_name', $user_name);
$stmt->bindValue(':password ', $password);
$stmt->execute();
Statement 2 – Based on this PDO wrapper https://github.com/Xeoncross/DByte/blob/master/DB.php (referenced in this post https://stackoverflow.com/a/12500462/1056713 )
static function insert($fit_table, array $fieldlist){
$query = "INSERT INTO`$fit_table`(`" . implode('`,`', array_keys('.$fieldlist.')). '`)
VALUES(' . rtrim(str_repeat('?,', count($fieldlist = array_values('.$vallist.'))), ',') . ')';
return DB::$p
? DB::column($query . 'RETURNING` user_id `', $fieldlist)
: (DB::query($query, $fieldlist) ? static::$c->lastInsertId() : NULL);
}
The full code for Statement 2 (This is how names are added dynamically at present)
// INSERT
$fieldlist=$vallist='';
foreach ($_POST as $key => $value) {
if ($key=='pants_waistband'){$value= implode(',',$value);}
$fieldlist.=$key.',';
$vallist.='\''.($value).'\',';
}
$fieldlist=substr($fieldlist, 0, -1);
$vallist=substr($vallist, 0, -1);
$fieldlist.=', user_id';
$vallist.=','.$user_id;
// UPDATE
$setlist='';
foreach ($_POST as $key => $value) {
if ($key=='pants_waistband'){$value= implode(',',$value);}
$setlist.=$key .'=\''.$value.'\',';
}
$setlist=substr($setlist, 0, -1);
$result = mysql_query('UPDATE fit_table SET '.$setlist.' WHERE user_id='.$user_id);
if (mysql_affected_rows()==0) {
$result = mysql_query('INSERT INTO fit_table ('.$fieldlist.') VALUES ('.$vallist.')');}
I’ve discovered that white listing names is far more secure than other methods (thanks to the help of several people, including @zerkms), and wanted to share the finished statement.
It’s now working properly, and includes the method required for connecting to the database with PDO. I also switched the db user account being used in the statement because I learned that it’s best to use an account with limited privileges (that can only SELECT, INSERT, and UPDATE) to minimize the damage that a hacker could do.