PHP PDO updating table [duplicate] - php

This question already has answers here:
When to use single quotes, double quotes, and backticks in MySQL
(13 answers)
Closed 5 years ago.
so I was following a Udemy course and then the instructor made this function
public function update($table, $user_id, $fields = array()){
$columns = '';
$i = 1;
foreach($fields as $name => $value){
$columns .= "'{$name}' = :{$name}";
if($i < count($fields)){
$columns .= ', ';
}
$i++;
}
$sql = "UPDATE {$table} SET {$columns} WHERE 'user_id' = {$user_id}";
if($stmt = $this->pdo->prepare($sql)){
foreach($fields as $key => $value){
$stmt->bindValue(':'.$key, $value);
}
$stmt->execute();
}
}
And I wrote it literally so many times after him and it just never seemed to work, would someone explain for me what's wrong with the code?

here
$sql = "UPDATE {$table} SET {$columns} WHERE 'user_id' = {$user_id}";
the ' around the table name should be backticks, not single quotes:
$sql = "UPDATE {$table} SET {$columns} WHERE `user_id` = {$user_id}";
same here:
$columns .= "`{$name}` = :{$name}";

You should replace single quotes with backticks:
$columns .= "`{$name}` = :{$name}";
and
$sql = "UPDATE {$table} SET {$columns} WHERE `user_id` = {$user_id}";
Just a suggestion: You could use an array to build the columns clause and you could directly execute without any bindValue, by just passing the $fields array:
function update($table, $user_id, $fields = array()) {
$columns = [];
foreach ($fields as $name => $value) {
$columns[] = "`{$name}` = :{$name}";
}
$sql = sprintf('UPDATE %s SET %s WHERE `user_id` = %s'
, $table
, implode(', ', $columns)
, $user_id
);
if ($stmt = $this->pdo->prepare($sql)) {
$stmt->execute($fields);
}
}

Related

Update Row Fields if POST['submitted_field'] Is Not Null MariaDB , MySQL

Hi I'm trying to update user information on valid submit
in my query it's possible to update multiple columns only if it's relevant $_POST[ ] is not null
how i can do that ? used tool php , MariaDB or mysql I. I tried something like this but it returns syntax error corresponding to MariaDB
$query = " UPDATE `users`
SET name = COALESCE($name, name),
title = COALESCE($title, title),
email = COALESCE($email, email),
gender = COALESCE($gender, gender)
WHERE `id` = '" . $_SESSION['id'] . "' LIMIT 1";
You can have a helper for doing that
function getUserUpdateQuery(array $data, $userId)
{
$condition = 'WHERE id = '.$userId;
$query = 'UPDATE `users` SET ';
$updates = [];
foreach ($data as $columnName => $columnValue) {
if( !is_null($columnValue) )
{
$updates[] = sprintf('`%s` = \'%s\'', $columnName, $columnValue);
}
}
$query .= implode(' AND ', $updates).' ';
$query .= $condition;
return $query;
}
$query = getUserUpdateQuery(['title' => $title, 'email' => $email], $_SESSION['id']);
// updating codes here
Note: in production environment it is better practice to bind data. PDO is a good tool for doing that.

PHP PDO UPDATE variable fields using IF

I have a function to update up to 3 fields in a mysql table. The function can receive all 3 fields to be updated or just 1 or 2
Right now I am doing it like this (it works) to construct MySQL statement.
if ($foo1){
$mysql_set = '`foo1` = :foo1';}
if ($foo2){
if ($mysql_set){$mysql_set .= ', ';}
$mysql_set .= '`foo2` = :foo2';}
if ($foo3){
if ($mysql_set){$mysql_set .= ', ';}
$mysql_set .= '`foo3` = :foo3';}
$update = $db->prepare("UPDATE `bar` SET $mysql_set WHERE `id` = :id");
if ($foo1){
$update->bindValue(':foo1', $foo1, PDO::PARAM_STR);}
if ($foo2){
$update->bindValue(':foo2', $foo2, PDO::PARAM_STR);}
if ($foo3){
$update->bindValue(':foo3', $foo3, PDO::PARAM_STR);}
$update->bindValue(':id', $id, PDO::PARAM_INT);
$update->execute();
As you can see I am repeating "if ($foo1 - $foo3){}" twice to construct this MySQL query. It looks redundant and wondering if there's a better way to handle this scenario.
You can give an associative array to execute(), instead of calling bindValue() separately for each parameter.
$param_array = array(':id' => $id);
$set_array = array();
if ($foo1) {
$param_array[':foo1'] = $foo1;
$set_array[] = "foo1 = :foo1";
}
if ($foo2) {
$param_array[':foo2'] = $foo2;
$set_array[] = "foo2 = :foo2";
}
if ($foo3) {
$param_array[':foo3'] = $foo3;
$set_array[] = "foo3 = :foo3";
}
if (!empty($set_array)) {
$set_string = implode(", ", $set_array);
$sql = "UPDATE bar SET $set_string WHERE id = :id";
$update = $db->prepare($sql);
$update->execute($param_array);
}
Try.
if ($foo1){
$mysql_set = '`foo1` = :foo1';
$update = prepareStmt($db, $mysql_set);
$update->bindValue(':foo1', $foo1, PDO::PARAM_STR);
}
if ($foo2){
if ($mysql_set){$mysql_set .= ', ';}
$mysql_set .= '`foo2` = :foo2';
$update = prepareStmt($db, $mysql_set);
$update->bindValue(':foo2', $foo2, PDO::PARAM_STR);
}
if ($foo3){
if ($mysql_set){$mysql_set .= ', ';}
$mysql_set .= '`foo3` = :foo3';
$update = prepareStmt($db, $mysql_set);
$update->bindValue(':foo3', $foo3, PDO::PARAM_STR);
}
$update->bindValue(':id', $id, PDO::PARAM_INT);
$update->execute();
function prepareStmt($db,$mysql_set){
return $db->prepare("UPDATE `bar` SET $mysql_set WHERE `id` = :id");
}

how to make an insert function with in a database class to insert a new record with multiple coloumns and multiple values (using PDO )?

the problem is my function insert inserts my record in two rows.
this is my code to connect to database in a file named :
connect.php
<?php
try{
$db = new PDO("mysql:host=localhost;dbname=NPD" , "root" , "");
echo "connected";
}
catch(Exception $e){
echo $e->getMessage();
}
this is my database class in a file
database.php
<?php
require 'connect.php';
class DB {
public function insertInto($tableName , $info){
global $db;
foreach ($info as $coloumnName => $coloumnValue) {
$stmt = $db->prepare("INSERT INTO $tableName ($coloumnName) VALUES ('$coloumnValue') ");
$stmt->execute();
}
}
}
$da = new DB;
$da->insertInto('tableOne',array('name' => 'lolo' , 'deg' => '100'));
the result in the database is :
tableOne
how can to make the insert function inserts my record in one row.
note : i want to insert any number of columns and values.
try to do something like this:
$arr = array('name' => 'lolo' , 'deg' => '100');
$columns=array_keys($arr);
$values=array_values($arr);
$str="INSERT INTO $tableName (".implode(',',$columns).") VALUES ('" . implode("', '", $values) . "' )";
echo $str;//your sql
// $stmt = $db->prepare($str);
// $stmt->execute();//uncomment to execute
Like this but there are some concerns ( also I haven't tested this )
class DB {
protected $_conn;
public function __construct( $user, $pass, $database='NPD', $host='localhost' ){
try{
$this->_conn = new PDO("mysql:host={$host};dbname={$database}" , $user , $pass);
echo "connected";
}catch(Exception $e){
echo $e->getMessage();
}
}
public function insertInto($tableName , $info){
$sql = 'INSERT INTO $tableName (';
$sql .= '`'implode('`,`', array_keys($info[0])).'`';
$sql .= ')VALUES';
foreach ($info as $index => $row) {
$sql .= '(';
foreach( $row as $column => $value){
$sql .= ':'.$column.$index.',';
$params[':'.$column.$index] = $value;
}
$sql = rtrim($sql, ',');
$sql .= '),';
}
$sql = rtrim($sql, ',');
$stmt = $this->_conn->prepare($sql);
$stmt->execute($params);
}
}
}
$da = new DB('root', '');
$da->insertInto('tableOne',array( array('name' => 'lolo' , 'deg' => '100') ) );
First of all you loose any sql injection protection on the column names. If you can manage the placeholders on the values, then that is ok, but without using them there you loose protection on that as well. This can be solved by using the db schema itself, via Show columns but that gets a wee bit complex.
https://dev.mysql.com/doc/refman/5.7/en/show-columns.html
Second, your input array structure is all wrong, it needs to be array(0=>array(...), 1=>array(...)) instead of just array(...)
Third I would make this class a "Singleton" but that's just me
http://coderoncode.com/design-patterns/programming/php/development/2014/01/27/design-patterns-php-singletons.html
Forth, if you just want to do a single row at a time you can change this method
public function insertInto($tableName , $info){
$sql = 'INSERT INTO $tableName (';
$sql .= '`'implode('`,`', array_keys($info)).'`';
$sql .= ')VALUES(';
$params = array();
foreach( $info as $column => $value){
$sql .= ':'.$column.$index.',';
$params[':'.$column.$index] = $value;
}
$sql = rtrim($sql, ',');
$sql .= ')';
$stmt = $this->_conn->prepare($sql);
$stmt->execute($params);
}
And use the current input array structure you have.
This Is how i coded my own insert function
public function insertRecord($table,$records){
//A variable to store all the placeholders for my PDO INSERT values.
$placeholder = '';
for ($i = 0; $i < sizeof($records); $i++){
$placeholder[$i] = '?';
}
//A FOR-LOOP to loop through the records in the $record array
$placeholder = implode(',', $placeholder);
//Imploding ',' in between the placeholders
$sql = "INSERT INTO ".$table." VALUES ("{$placeholder}")";
$query = $this->dbh->prepare($sql);
$query->execute($records);
}
It Might not be the best..worked for me though.
As some other answers/comments have stated, there are quite a few critiques one could make about this overall process. However, in the interests of simply answering the question, you may want to just build the statement by looping through the columns, then looping through the values, then executing the finished statement (code below is just an example and hasn't been tested):
require 'connect.php';
class DB {
public function insertInto($tableName , $info){
global $db;
$query = "INSERT INTO $tableName (";
$columns = array_keys($info);
// build the columns in the statement
$length = count($columns);
foreach($columns as $index => $column) {
$query .= "$column";
if ($index+1 < $length) {
$query .= ','
}
}
$query .= ") VALUES ("
// build the values in the statement
$i = 1;
$length = count($info);
foreach($info as $value) {
$query .= "'$value'"
if ($i < $length) {
$query .= ","
}
$i++;
}
$query .= ")"
$stmt = $db->prepare($query);
$stmt->execute();
}
}
$da = new DB;
$da->insertInto('tableOne',array('name' => 'lolo' , 'deg' => '100'));

PHP and PDO prepared statments - Column not found

I have a problem with a "unknown" column.
This is the error I get back in firebug.
ERROR: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'admin' in 'where clause'UPDATE users SET session_key = 1234567890 WHERE username = 'admin'
this is the parameters and call statement
$table = 'users';
$fields_vals = array( 'session_key' => $session_key );
$where = array('username' => $username);
$dbResult = $this->DB->sql_update($fields_vals, $table, $where);
/*
* UPDATE
* $data -> assoc array containing (field => value) to be UPDATED.
* $where -> Where clause (only a single argument)
* $table -> to be updated
*/
public function sql_update($fieldsVals, $table, $where)
{
try {
//Values to be updated in in a assoc array
//Extract values and fields and concatenate with '=' ( field = value )
$upd_string = '';
foreach($fieldsVals as $name => $value){
$upd_string .= $name .' = :'. $name .' ,';
}
//Trim last comma that was appended
$upd_string = rtrim($upd_string, ',');
// Formulate the where clause
$where_str = '';
foreach($where as $wName => $wValue){
$where_str .= "$wName = $wValue";
}
//Set Query
//$query = "UPDATE {$table} SET {$upd_string} WHERE $where_str";
// THIS IS WHERE I EXPLICITLY RAN THE QUERY, BUT GOT EXACTLY THE SAME ERROR.
$query = "UPDATE users SET session_key = 1234567890 WHERE username = 'admin'";
$stmt = $this->conn->prepare($query);
//Exec
foreach($fieldsVals as $k => &$v){
$stmt->bindParam(":{$k}", $v);
}
$stmt->execute();
return true;
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
return false;
}
}
Here is proof that the column does exist.
PLEASE NOTE -> where username = 'admin'
Try passing your WHERE attribute in as a prepared variable:
$query = "UPDATE users SET session_key = 1234567890 WHERE username = :username";
$fieldsVals[":username"] = "admin";
$where_str .= "$wName = '$wValue'";
Otherwise your query comes as "WHERE username = admin"
What you should do to use prepared statements for the whole query, so you should change your function from the current one into:
function sql_update($fieldsVals, $table, $where)
{
//Values to be updated in in a assoc array
//Extract values and fields and concatenate with '=' ( field = value )
$upd_string = '';
foreach ($fieldsVals as $name => $value) {
$upd_string .= $name . ' = :set_' . $name . ' ,';
}
//Trim last comma that was appended
$upd_string = rtrim($upd_string, ',');
// Formulate the where clause
$where_str = '';
foreach ($where as $wName => $wValue) {
$where_str .= $wName . ' = :wh_' . $wName . ' ,';
}
//Trim last comma that was appended
$where_str = rtrim($where_str, ',');
//Set Query
$query = "UPDATE {$table} SET {$upd_string} WHERE $where_str";
$stmt = $this->conn->prepare($query);
//Exec
foreach ($fieldsVals as $k => &$v) {
$stmt->bindParam(":set_{$k}", $v);
}
foreach ($where as $k => &$v) {
$stmt->bindParam(":wh_{$k}", $v);
}
$stmt->execute();
return true;
}
The correct usage would be:
$stmt = $this->conn->prepare('UPDATE users SET session_key = :session WHERE username = :username');
$stmt->bindParam(':session', session_id(), PDO::PARAM_STR);
$stmt->bindParam(':username', $username, PDO::PARAM_STR);
Then execute.
I think your variable $fieldsVals is wrong due to the foreach's you do. Maybe you switching key und val by accident, resulting in WHERE admin=username.
Update:
#MarcinNabiaƂek is right of course you are missing quotes.
But it seems like the error is coming from a different part of the script.
It seems you don't use ' in your query in PHP. Either you don't use it or use other symbol that look similar.
If I run in phpmyAdmin query:
UPDATE users SET session_key = 1234567890 WHERE username = admin
I also get error message:
#1054 - Unknown column 'admin' in 'where clause'
but when I have
UPDATE users SET session_key = 1234567890 WHERE username = 'admin'
it works fine
In your code you should definitelly change:
$where_str .= "$wName = $wValue";
into
$where_str .= "$wName = '$wValue'";
session_key is a varchar
You have to use the query like the below,
$query = "UPDATE users SET session_key = '1234567890' WHERE username = 'admin'";
column admin doesn't exist! column administrator exists though.
I don't see any admin column in your mysql table in the screenshot that you provided.
You can simply change the name of the administrator column in your mysql table to admin and everything will work.

building db query with a for loop

I've made a function to query the database. This function takes an array, the id of the user I want to update
and a query operation.
if the query operation is UPDATE
if you look at the code below, would this be a good coding practice or is this bad code?
public function query($column, $search_value, $query_operation = "SELECT"){
if(strtoupper($query_operation == "UPDATE")){
$query = "UPDATE users SET ";
if(is_array($column)){
$counter = 1;
foreach($column as $key => $value){
if($counter < count($column)){
$query .= $key . ' = ?, ';
}else{
$query .= $key . ' = ? ';
}
$counter++;
}
$query .= "WHERE id = ?";
$stmt = $this->database->prepare($query);
$counter = 1;
foreach($column as $key => &$value){
$stmt->bindParam($counter, $value);
$counter++;
}
$stmt->bindParam($counter, $search_value);
if($stmt->execute()){
$stmt = $this->database->prepare("SELECT* FROM
users WHERE id = ?");
$stmt->bindParam(1, $search_value, PDO::PARAM_INT);
$stmt->execute();
return $this->build_array($stmt);
}
}
}
}
would love to hear some feedback.
I would NOT mix SELECT and UPDATE in the same function.
The following update function uses arrays for column names and values $columnNames & $values using unnamed parameters.
function update($tableName,$columnNames,$values,$fieldName,$fieldValue){
$sql = "UPDATE `$tableName` SET ";
foreach($columnNames as $field){
$sql .= $field ." = ?,";
}
$sql = substr($sql, 0, -1);//remove trailing ,
$sql .= " WHERE `$fieldName` = ?";
return $sql;
}
As table and column names cannot be passed as parameters in PDO I have demonstrated whitelistng of table names.
$tables = array("client", "Table1", "Table2");// Array of allowed table names.
Also array_push()to add value for last parameter (WHERE) into $values array
Use
if (in_array($tableName, $tables)) {
$sql = update($tableName,$columnNames,$values,$fieldName,$fieldValue);
array_push($values,$fieldValue);
$STH = $DBH->prepare($sql);
$STH->execute($values);
}
You can use similar technique for SELECT

Categories