Flexible function for updating DB records from PHP - php

Is there any way to make the below-given code reusable for different tables, e.g. using foreach? So, how to send and use arrays of column names and values? Any example is highly appreciated.
<?php
include_once 'include/DatabaseConnector.php';
if(isset($_POST['flightNum'])) {
$flightNum=$_POST['flightNum'];
$from=$_POST['from'];
$STADate=$_POST['STADate'];
$query = 'UPDATE flightschedule
SET frm="'.$from.'",STADate="'.$STADate.'"
WHERE flightNum="'.$flightNum.'"';
DatabaseConnector::ExecuteQuery($query);
echo '1';
} else {
echo '0';
}
?>
UPDATE: What if I don't know column names apriori? How to create flexible UPDATE statement?

you can convert your code into a reusable function. for example.
function updateDB($tableName, $flightNum, $from, $STADate) {
include_once 'include/DatabaseConnector.php';
$query = 'UPDATE ' . $tableName
SET frm="'.$from.'",STADate="'.$STADate.'"
WHERE flightNum="'.$flightNum.'"';
$execute = DatabaseConnector::ExecuteQuery($query);
return $execute;
}
and to use it
if(isset($_POST['flightNum']) {
$update = updateDB('flightschedule', $_POST['flightNum'], $_POST['from'], $_POST['STADate']);
echo $update;
}
Update:
I want to send an array of column names to the function 'updateDB'.
Let's say these are column names for SET and WHERE parts of UPDATE
statement. And then I could use FOREACH, but I need some example for
this.
this is how you can do it.
function updateDB($tableName, $columns, $where) {
//do some validation here to check if proper data is being passed like
if(!isarray($columns)) {
throw new Exception('argument two $columns should be an associative array');
}
include_once 'include/DatabaseConnector.php';
$query = 'UPDATE ' . $tableName;
foreach($columns as $column => $data) {
$query .= ' SET ' . $column . ' = ' . $data . ', ';
}
//remove last comma from the update query string
$query = substr($query, 0, -1);
$query .= ' WHERE ' . $where['column'] . ' = ' . $where['value'];
$execute = DatabaseConnector::ExecuteQuery($query);
return $execute;
}
and to use it.
if(isset($_POST['flightNum']) {
$columns = array(
'frm' => $_POST['frm'],
'STADate' => $_POST['STADate']
);
$where = array(
'column'=> 'flightNum',
'value' => $_POST['flightNum']
);
$update = updateDB('flightschedule', $columns, $where);
echo $update;
}

Something like this should work:
function generateUpdateQuery($table, $fields, $where) {
$updateFields = array();
foreach ($fields as $k => $v) {
$updateFields[] = $k.' = \''.$v.'\'';
}
$sqlQuery = 'UPDATE '.$table.
' SET '.implode(', ', $updateFields).
' WHERE '.implode(' AND ', $where);
return $sqlQuery;
}
echo generateUpdateQuery('table_name',
array(
'field_a' => '10',
'field_b' => 'hello',
'field_c' => 'world'),
array(
'id=12',
'datetime > NOW()')
);
Keep in mind that this is a simple example without any security check. Something like PDO would be recommended.
Moreover, if you're looking for something more robust and flexible you should give a look to a ORM system, like Doctrine

Related

PDO Function simplification

Here is my function.
I want to simplify this function.
Any one help me please?
public function showData($table,$fields,$values)
{
$first = true;
$whereClause=null;
foreach($fields as $key => $value)
{
if($first)
{
$whereClause .= " WHERE $value = '$values[$key]'";
$first = false;
}
else
{
$whereClause .= " AND $value = '$values[$key]'";
}
}
$sql = "SELECT * FROM $table $whereClause";
$q = $this->conn->prepare($sql) or die("failed!");
$q->execute();
while ($r = $q->fetch(PDO::FETCH_ASSOC))
{
$data[] = $r;
}
return $data;
}
foreach($ob->showData($tablenm,$field,$val) as $roleval)
{
//Do Something
}
Any other way to simplify this function.
Help me please.
public function query($sql, $params = NULL)
{
$stmt = $this->conn->prepare($sql);
$stmt->execute($params)
return $stmt;
}
$data = $ob->query("SELECT * FROM table WHERE foo = ? AND bar = ?", [$foo, $bar]);
foreach($data as $roleval)
{
//Do Something
}
This function is way more simpler, way more powerful and way more flexible than yours. Put aside that yours is essentially and irrecoverably prone to SQL injection, just mocking a prepared statement but not using it really.
You have to understand that keywords in SQL serve for the great purpose of readability, makes whole statement readable and unambiguous, comprehensible by the every programmer in the world. And so you can tell that your initial idea to save yourself typing of SELECT or WHERE turns to be not that brilliant.
Besides, PDO supports dozens of different return formats, while you are limiting yourself with only one.
You may read further in my article Your first database wrapper's childhood diseases
function showData($table, $fields, $values) {
if(!(is_array($fields) && is_array($values) ) || count($fields) !== count($values))
throw new Exception('Arguments error: "fields" and "values" must be arrays with equal number of elements.');
foreach ($fields as $key => &$field)
$field = '`' . str_replace('`', '``', $field) . '` = ' . $this->conn->quote($values[$key]);
return 'SELECT * FROM `' . str_replace('`', '``', $table) . (empty($fields) ? '`' : '` WHERE ' . implode(' AND ', $fields)) . ';';
}
test case:
echo showData('table`name', ['col`1', 'col\`2', 'col\\`3'], ["Tom's cat 1", "Tom's cat 2", "Tom's cat 3"]);
#output: SELECT * FROM `table``name` WHERE `col``1` = 'Tom\'s cat 1' AND `col\``2` = 'Tom\'s cat 2' AND `col\``3` = 'Tom\'s cat 3';
Of course you will execute the SQL instead of returning it as test output.

store associative array into single line for sql update

I want to take an associative array and parse that to put into the SET part of an UPDATE query:
My call with the associative array:
$this->ccQuery( 'emails', array('user_id' => $id, 'email_address' => $request->email) );
function ccQuery( $t, $a, $id=null )
{
foreach($a as $key=>$value)
{
$setfields[] = $key . "='" . $value . "'";
}
$setfields = implode(', ', $setfields);
$testquery2 = 'UPDATE mytable_'.$t.' SET ' .$setfields. ' WHERE user_id="'.$user_id;
...
}
setfields is empty. What am I doing wrong?
Maybe something like:
...
$testquery2 = "UPDATE mytable_"
foreach($a as $key=>$value)
{
$testquery2 = $testquery2 ."$t SET '$value' WHERE user_id= '$id'";
}
...

NotORM: How to fetch data?

I´m having trouble using selects, I tried reading the documentation but it's not too clear, and the forums that talk about it are few and inactive.
I want to do a simple select, so I tried:
$applications = $NOTORM->user_types()
->select('id, group_title')
->where('id', 1);
return $applications;
That however gives me back a NotORM object where I don't see the resulting rows that I get when I do a normal: SELECT id, group_title FROM user_types WHERE id = 1
I tried using the fetch() but not really sure how to use it. Any insights?
Actually, recommended by the author of NotORM is to use:
<?php
array_map('iterator_to_array', iterator_to_array($result));
?>
Good luck!
I had the same problem till I realized that you have to loop over result.
Try
foreach($applications as $application) {
echo $application["id"] . ": " . $application["group_title"]
}
Alternatively as you mentioned you can use fetch() which will fetch you one row at a time.
$row=$applications->fetch();
echo $row["id"];
EDIT:
To get all the row data as plain associative array instead of NotORM Object I have come across 2 techniques:
foreach($row as $key => $value) {
$data[$key]=$value;
}
$data=iterator_to_array($row); - I haven't fount a NotOrm function that does this but I found that Notorm uses this technique internally(somewhere).
To actually get only the data array of the row, you have to access NotORM_Row->row param, but it is 'protected' by default. So to use it like this:
$row = $NOTORM->user_types()
->select('id, group_title')
->where('id', 1)
->fetch()->row; //here is the magic :)
You first need to 'hack' core NotORM_Row class in 'NotORM/Row.php',
by replacing
protected $row, $result;
to
public $row, $result;
Note: You have to call fetch() on NotORM results, because it will return the NotORM_Row object where the row data is placed.
Just add this code somewhere inside the NotORM_Result class:
function result() { return (Object)$this->result_array(); }
function result_array() {
foreach($this as $row) { $ret[] = iterator_to_array($row); }
return $ret;
}
And use it like:
$applications = $NOTORM->user_types()
->select('id, group_title')
->where('id', 1);
return $applications->result(); //To return it as an Plain Object
//or
return $applications->result_array(); //To return it as a Assoc Array
Try to define this PHP function:
function getArray($obj){
$arr = array();
foreach ($obj as $objSingle) {
$arrRow = array();
foreach ($objSingle as $key => $value) {
$arrRow[$key] = $value;
}
$arr[] = $arrRow;
}
return $arr;
}
And use it by calling:
$arr = getArray($applications);
NotOrm added a function that return raw row data than names jsonSerialize. You can get row data array by this function.
Example:
$row=$db->MyTable->where('X','93054660084')->fetch();
var_dump($row->jsonSerialize());
Output:
array (size=5)
'X' => string '93054660084' (length=9)
'Idc' => string '1132' (length=4)
'IdH' => string '1' (length=1)
'Mab' => string '0' (length=1)
'Tar' => string 'xsderf' (length=10)
For multi record data you need to use foreach and apply it to all records.
It can be done like this.
function comboBuilder2($tbl, $name, $lable, $value, $value2, $value3, $selected = NULL, $cond, $sort = NULL){
global $db;
$html = '';
$sort1 = (!empty($sort)) ? "order by sort asc" : '';
$sql = "select * from " . $tbl . " " . $cond . " " . $sort1 . "";
//echo $sql;
$sth = $db->query($sql);
$rs = $sth->fetchAll();
//print_r($rs);
if ($rs[0] > 0) {
foreach ($rs as $row) {
if ($selected == $row[$value])
$sel = 'selected = "selected" ';
else
$sel = '';
echo $row[$lable];
//$html .= '<option value="' . $row[$value] . '" data-min="' . $row[$value2] . '" data-max="' . $row[$value3] . '" ' . $sel . '>' . $row[$lable] . '</option>';
}
$html .= '';
}
return $html;
}

insert multiple data

how i do wrong i want insert to db data from array:
$tabb = array(
'name' => 'test',
'login' => 'testt');
but i cant use SET, because end of query is char , .
public function insert($table, $values){
if($this->database){
print_r($values);
$we = 'INSERT INTO '. $table .' SET ';
foreach($values as $value => $key) {
$we .= ' ('. $value .' = "'. $key .'") ';
}
print $we;
mysql_query($we);
}
return true;
}
i do print $we:
INSERT INTO user SET (name = "test") (login = "testt")
not work, please help
php
I really recommend avoiding SET. It is far less common and given the choice between something which is uncommon and something which is common, always go with the common -- it means broader, faster, and better support by your community.
Here's how you'd approach that problem without it:
If you only have two columns in your USER table, you can simply use VALUES followed by a comma delineated list of data sets:
INSERT INTO user VALUES ("test","testt"),("test2","testt2")
Your function doesn't look like it is geared towards this, but it is a good thing to know either way.
But it looks like you are inserting by column name (a good idea in general):
INSERT INTO user (name, login) VALUES ("test","testt")
With PHP this becomes:
$items = array_map('mysql_real_escape_string', $values);
$items = '(\'' . implode( '\',\'', $items ) . '\')';
$q = 'INSERT INTO '.
$table .
// using implode with array_keys assumes that you know all of the keys
// ahead of time. If you don't, I MUST suggest your re-think your code
// omit the following line if you want to follow the first SQL example
' (' . implode( ',', array_keys( $values ) . ') '.
' VALUES ' .
$items;
public function insert($table, $values){
$fields = array();
$data = array();
foreach ($values as $key => $val) {
$fields[] = mysql_real_escape_string($key);
$data[] = mysql_real_escape_string($val);
}
$fields = implode(',', $fields);
$data = implode(',', $data)
$sql = "INSERT INTO $table ($fields) VALUES ($data);"
mysql_query($sql) or die(mysql_error());
}
public function insert($table, $values)
{
if($this->database)
{
print_r($values);
$we = 'INSERT INTO '. $table .' SET ';
$sep = '';
foreach($values as $value => $key)
{
$we .= $sep . ' ('. $value .' = "'. mysql_real_escape_string($key) .'") ';
$sep = ',';
}
print $we;
mysql_query($we);
}
return true;
}
Or, if you want to be tricky:
public function insert($table, $values)
{
if($this->database)
{
print_r($values);
$we = "insert into `".$table. "` (`". implode('`,`',array_keys($fields))."`) values ('".implode("','",array_map('mysql_real_escape_string', $fields))."');";
print $we;
mysql_query($we);
}
return true;
}
You need to seperate (name = "test") (login = "testt") with ", " between them (name = "test"), (login = "testt")
Another way is to do it is:
INSERT INTO user (name, login) VALUES ("test", "testt")

PHP Implode Associative Array

So I'm trying to create a function that generates a SQL query string based on a multi dimensional array.
Example:
function createQueryString($arrayToSelect, $table, $conditionalArray) {
$queryStr = "SELECT ".implode(", ", $arrayToSelect)." FROM ".$table." WHERE ";
$queryStr = $queryStr.implode(" AND ",$conditionalArray); /*NEED HELP HERE*/
return $queryStr;
}
$columnsToSelect = array('ID','username');
$table = 'table';
$conditions = array('lastname'=>'doe','zipcode'=>'12345');
echo createQueryString($columnsToSelect, $table, $conditions); /*will result in incorrect SQL syntax*/
as you can see I need help with the 3rd line as it's currently printing
SELECT ID, username FROM table WHERE
lastname AND zipcode
but it should be printing
SELECT ID, username FROM table WHERE
lastname = 'doe' AND zipcode = '12345'
You're not actually imploding a multidimensional array. $conditions is an associative array.
Just use a foreach loop inside your function createQueryString(). Something like this should work, note it's untested.:
$terms = count($conditionalArray);
foreach ($conditionalArray as $field => $value)
{
$terms--;
$queryStr .= $field . ' = ' . $value;
if ($terms)
{
$queryStr .= ' AND ';
}
}
Note: To prevent SQL injection, the values should be escaped and/or quoted as appropriate/necessary for the DB employed. Don't just copy and paste; think!
function implodeItem(&$item, $key) // Note the &$item
{
$item = $key . "=" . $item;
}
[...]
$conditionals = array(
"foo" => "bar"
);
array_walk($conditionals, "implodeItem");
implode(' AND ', $conditionals);
Untested, but something like this should work. This way you can also check if $item is an array and use IN for those cases.
You will have to write another function to process the $conditionalArray, i.e. processing the $key => $value and handling the types, e.g. applying quotes if they're string.
Are you just dealing with = condition? What about LIKE, <, >?
Forgive me if its not too sexy !
$data = array('name'=>'xzy',
'zip'=>'3432',
'city'=>'NYK',
'state'=>'Alaska');
$x=preg_replace('/^(.*)$/e', ' "$1=\'". $data["$1"]."\'" ',array_flip($data));
$x=implode(' AND ' , $x);
So the output will be sth like :
name='xzy' AND zip='3432' AND city='NYK' AND state='Alaska'
I'd advise against automated conditionals creation.
Your case is too local, while there can be many other operators - LIKE, IN, BETWEEN, <, > etc.
Some logic including several ANDs and ORs.
The best way is manual way.
I am always doing such things this way
if (!empty($_GET['rooms'])) $w[]="rooms='".mesc($_GET['rooms'])."'";
if (!empty($_GET['space'])) $w[]="space='".mesc($_GET['space'])."'";
if (!empty($_GET['max_price'])) $w[]="price < '".mesc($_GET['max_price'])."'";
Though if you still want it with this simple array, just iterate it using
foreach ($conditions as $fieldname => $value)...
and then combine these variables in the way you need. you have 2 options: make another array of this with field='value' pairs and then implode it, or just concatenate, and substr trailing AND at the end.
I use a variation of this:
function implode_assoc($glue,$sep,$arr)
{
if (empty($glue)) {$glue='; ';}
if (empty($sep)) {$sep=' = ';}
if (is_array($arr))
{
foreach ($arr as $k=>$v)
{
$str .= $k.$sep.$v.$glue;
}
return $str;
} else {
return false;
}
};
It's rough but works.
Here is a working version:
//use: implode_assoc($v,"="," / ")
//changed: argument order, when passing to function, and in function
//output: $_FILES array ... name=order_btn.jpg / type=image/jpeg / tmp_name=G:\wamp\tmp\phpBDC9.tmp / error=0 / size=0 /
function implode_assoc($arr,$glue,$sep){
$str = '';
if (empty($glue)) {$glue='; ';}
if (empty($sep)) {$sep=' = ';}
if (is_array($arr))
{
foreach ($arr as $key=>$value)
{
$str .= $key.$glue.$value.$sep;
}
return $str;
} else {
return false;
}
}
I know this is for the case of a pdo mysql type.. but what i do is build pdo wrapper methods, and in this case i do this function that helps to build the string, since we work with keys, there is no possible way to mysql inject, since i know the keys i define / accept manually.
imagine this data:
$data=array(
"name"=>$_GET["name"],
"email"=>$_GET["email"]
);
you defined utils methods...
public static function serialize_type($obj,$mode){
$d2="";
if($mode=="insert"){
$d2.=" (".implode(",",array_keys($obj)).") ";
$d2.=" VALUES(";
foreach ($obj as $key=>$item){$d2.=":".$key.",";}
$d2=rtrim($d2,",").")";}
if($mode=="update"){
foreach ($obj as $key=>$item){$d2.=$key."=:".$key.",";}
}
return rtrim($d2,",");
}
then the query bind array builder ( i could use direct array reference but lets simplify):
public static function bind_build($array){
$query_array=$array;
foreach ($query_array as $key => $value) { $query_array[":".$key] = $query_array[$key]; unset($query_array[$key]); } //auto prepair array for PDO
return $query_array; }
then you execute...
$query ="insert into table_x ".self::serialize_type( $data, "insert" );
$me->statement = #$me->dbh->prepare( $query );
$me->result=$me->statement->execute( self::bind_build($data) );
You could also go for an update easy with...
$query ="update table_x set ".self::serialize_type( $data, "update" )." where id=:id";
$me->statement = #$me->dbh->prepare( $query );
$data["id"]="123"; //add the id
$me->result=$me->statement->execute( self::bind_build($data) );
But the most important part here is the serialize_type function
Try this
function GeraSQL($funcao, $tabela, $chave, $valor, $campos) {
$SQL = '';
if ($funcao == 'UPDATE') :
//Formata SQL UPDATE
$SQL = "UPDATE $tabela SET ";
foreach ($campos as $campo => $valor) :
$SQL .= "$campo = '$valor', ";
endforeach;
$SQL = substr($SQL, 0, -2);
$SQL .= " WHERE $chave = '$valor' ";
elseif ($funcao == 'INSERT') :
//Formata SQL INSERT
$SQL = "INSERT INTO $tabela ";
$SQL .= "(" . implode(", ", array_keys($campos) ) . ")";
$SQL .= " VALUES ('" . implode("', '", $campos) . "')";
endif;
return $SQL;
}
//Use
$data = array('NAME' => 'JOHN', 'EMAIL' => 'J#GMAIL.COM');
GeraSQL('INSERT', 'Customers', 'CustID', 1000, $data);

Categories