How to execute prepare statement using if statement in PHP PDO? - php

I am fetching some data from MySQL database using PHP PDO prepared statement. I have to use if statement inside the execution of the prepared statement. See my codes below for better understanding
$query = "SELECT * FROM my_table WHERE 1=1";
if(isset($_GET['one'])){
$query .= " AND one = :one";
}
if(isset($_GET['two'])){
$query .= " AND two = :two";
}
if(isset($_GET['three'])){
$query .= " AND three = :three";
}
$result = $db->prepare($query);
$result->execute([
/* ------------------------------------
How to declare the above parameters here
as it will show error if any of the if statement is not true?
----------------------------------------*/
]);
I want to know how to declare the prepared array parameter using if statement inside the $result->execute(......]) block?

You need to create an empty $params array, and inside each if block you can push the appropriate value to it. For example:
if(isset($_GET['one'])){
$query .= " AND one = :one";
$params[':one'] = $_GET['one'];
}
Then you can simply do
$result->execute($params);
Note that you can based on what you've written, you could simplify your code with an outer foreach on a list of parameter names e.g.
$names= array('one', 'two', 'three');
$params = array();
foreach ($names as $name) {
if (isset($_GET[$name])) {
$query .= " AND $name = :$name";
$params[":$name"] = $_GET[$name];
}
}
$result->execute($params);

Related

PHP - add new WHERE clause to SQL statement within foreach loop

I've got a checkbox filter where multiple options can be 'checked'. Once they are checked they are stored in a JavaScript array and passed to the php file via ajax. From there, I'm trying to do a foreach loop to get each element in the array and add a new where condition to the SQL statement for each element, and run the query.
JavaScript
var vendors = [];
function filterResults($this)
{
var vendor = $($this).attr('data-id');
if($($this).prop('checked'))
{
var action = 'add';
vendors.push(vendor);
}
else
{
var action = 'remove';
var index = vendors.indexOf(vendor);
if(index >= 0)
{
vendors.splice(index, 1);
}
}
PHP Script that is run (filter-results.php)
if(is_array($_POST['vendors']))
{
$collaterals = $vendor->updateResults($_POST['vendors']);
var_dump($collaterals);
foreach($collaterals as $col)
{
include '../parts/item.php';
}
}
PHP Function containing foreach loop
public function updateResults($vendors)
{
try
{
$items = array();
$sql = "SELECT * FROM collaterals WHERE ";
foreach ($vendors as $ven)
{
echo $ven;
$sql .= "vendor = ".$ven." OR ";
}
$stmt = $this->db->prepare($sql);
$stmt->execute();
while($row = $stmt->fetchObject())
{
$items[] = $row;
}
return $items;
}
catch(Exception $e)
{
$e->getMessage();
}
}
The 'echo' within the PHP function is working, but the var_dump() is turning 'NULL' which means there is an error within the SQL statement somewhere.
Any help would be greatly appreciated. Thanks!
You can this run query without foreach loop as follows
$sql = "SELECT * FROM collaterals WHERE vendor IN ('".implode("','",$vendors)."')";
Your query looks like
SELECT * FROM collaterals WHERE vendor = x OR vendor = x OR
You must remove the last OR.
Also i would suggest using the IN clause with implode() php function.
it will produce "SELECT * FROM collaterals WHERE vendor = 1 OR vendor = 2 OR "
use "Select * FROM collaterals where vendor in(1,2,3)" instead,
Problems:
You're using vendor = item1 OR vendor = item2 OR (notice the hanging OR)
Using IN achieves the same result
You should be using prepared statements
Do this:
$items = array();
$sql = "SELECT * FROM collaterals WHERE vendor IN (".
implode(",",array_fill(0, count($vendors), "?"))
.")";
// $sql would look like e.g. SELECT * FROM collaterals WHERE vendor IN (?,?,?)
$stmt = $this->db->prepare($sql);
$stmt->execute($vendors);
Note: All $vendors will be treated as strings in the above code, if you need to bind them as a different type you should call bindParam or bindValue on each array entry

update table using dynamic prepared statements

I'm trying to accomplish dynamic PDO prepared UPDATE statements using a customized array filled with $_POST data.The array structure looks like this:
$data = array();
$data[00001] = array("description"=>"item1", "stock"=>"100");
$data[00002] = array("description"=>"item2", "thr_alert"=>"20");
The mysql columns have the same name as the array keys. The 'id' is the main array key (00001, 00002, etc).
My first approach was the method described here: php.net pdo execute()
foreach($data as $itemId=>$value) {
$keys = array_keys($value);
$fields = '`'.implode('`, `',$keys).'`';
$placeholder = substr(str_repeat('?,',count($keys)),0,-1);
echo "INSERT INTO `baz`($fields) VALUES($placeholder)";
print_r(array_values($value)); //values to fill up execute() later on
echo "<br>";
}
unset($keys, $fields, $placeholder, $itemId, $value);
Nice approach but doesn't work, as this is designed for INSERT prepared statements and can't be used for UPDATE as the syntax should be UPDATE foo SET bar = :bar/? WHERE id = :id/?.Second approach:
$out = "UPDATE `baz` SET ";
foreach($data as $itemId=>$value) {
foreach($value as $column=>$foo) {
}
$out1 .= $column." = :$column, ";
$out2 = "WHERE id = :id";
}
$output = $out.rtrim($out1, ", ")." ".$out2."<br>";
echo $output;
Output:
UPDATE baz SET stock = :stock, description = :description WHERE id = :id
Notice that only the first array is displayed.
Any ideas on how to achive my goal ?
Move this line inside the second foreach loop
$out1 .= $column." = :$column, ";
But the result is awkward for the current data,since it will generate something like
...SET description = :description,description = :description....
Solved!I had to unset($out1); after $output is written and execute the $out1 line in the second foreach loop (see code below).
$out = "UPDATE `foo` SET ";
foreach($data as $itemId=>$value) {
foreach($value as $column=>$foo) {
$out1 .= $column." = :$column, ";
}
$out2 = "WHERE id = :id";
$output .= $out.rtrim($out1, ", ")." ".$out2."<br>";
unset($out1);
}
echo $output;
The next step will be to prepare the statement using $db->prepare($output); and pass the data to $db->execute($data);.
So to answer my own question - yes, dynamic prepared statements using one "global" array IS possible ! :-)

How to execute a PostgreSQL PREPARE query with IN () parameters

I'm trying to prepare a query from PHP like:
pg_prepare($con, "prep", "select * from test where tid in ($1)");
and then execute it with:
$strpar = "3,4,6,8,10";
pg_execute($con, "prep", array($strpars));
The problem is that I cannot pass a series of values built as prepare expects a fixed number of parameters. Is there any way to make the parameters dynamic?
Use an array to represent the series of values:
pg_prepare($con, "prep", "select * from test where tid=ANY($1)");
$strpar = "{3,4,6,8,10}";
pg_execute($con, "prep", array($strpars));
You can also create a PHP function to receive a PHP array and set it as a valid array for a Postgres prepared statement as in:
function php_array_to_pg ($array) {
$values = "";
foreach ($array as $value) {
if ($values=="") {
$values = $value;
} else {
$values = $values.",".$value;
}
}
return "{".$values."}";
}
Then you make a statement such as:
pg_prepare($con, "prep", "select * from test where tid=ANY($1)");
$array = array(1,2,3,4);
pg_execute($con, "prep", array(php_array_to_pg ($array)));

Execute unique query after foreach loop php

I have to update a mysql table with values that comes from array variable in size.
For that i was doing something like this but this code execute many query as the number of items on the array, and is hard to manage errors.
how i can execute only one query but still using a foreach loop?
the php version of server is so old does not support anything else than mysql_query.
foreach($decoded_array as $key=>$value)
{
if(!is_numeric($value))
{
$value = "'".$value."'";
}
echo $sql ="UPDATE table SET ".$key." = ".$value.";
$res = mysql_query($sql);
}
$set = "";
foreach($decoded_array as $key=>$value)
$set .= ($set ? "," : "") . $key . "=" . (is_numeric($value) ? $value : "'".$value."'");
$sql = "UPDATE table SET " . $set;
$res = mysql_query($sql);
But im not sure using "'".$value."'" is safe. I prefer mysqli function escape_string.
echo $sql ="UPDATE table SET ".$key." = ".$value.";
change this to this
$sql ="UPDATE table SET '".$key."' = '".$value."';
and this
$value = "'".$value."'";
to this
$value = '".$value."';
one more think mysql_ function are depricited.
use mysqli_ Function or PDO
For mysqli_ function check this link http://php.net/manual/en/book.mysqli.php
FOR PDO check this link http://php.net/manual/en/book.pdo.php

creating a flexible update query with Php and pdo - problems with bindparam

I'm updating my mysql functions to use PDO. I've got the hang of most of it but struggling with an update function to update multiple fields in a records.
The function is in a class and I'm trying to keep it flexible to reuse with other tables etc.
Here's my function so far:
public function dbUpdateRecord($table, $values, $where)
{
$this->conn();
$fieldNames = array_keys($values);
var_dump($fieldNames);
$set="";
foreach ($fieldNames as $field) {
$set .= " $field = :$field,";
}
//strip last comma
$set = substr($set, 0, strlen($set) - 1);
$wherefields = array_keys($where);
$whereCondition="";
foreach ($wherefields as $field) {
$whereCondition .= " $field = :$field AND";
}
//strip last AND
$whereCondition = substr($whereCondition, 0, strlen($whereCondition) - 3);
$sql = "UPDATE $table SET $set WHERE $whereCondition";
var_dump($sql);
$stmt = $this->db->prepare($sql);
foreach ($values as $field => $value) {
$stmt->bindParam(':$field', $value);
}
foreach ($where as $field => $value) {
$stmt->bindParam(':$field', $value);
}
return $stmt->execute();
}
The problem is all the fields in the record are being updated by the id of the record which is contained in the $where variable.
$values contains an array of (fieldname=>value).
I think the problem lies around the bindparam and trying to make the fieldnames/placeholders dynamic
I thought I needed to use bindparam as best practice - is this correct or can I just go to execute()?
ANy help appreciated
You are lifting this log from the wrong end.
Your approach is potentially insecure yet inflexible at the same time.
What if you need a JOIN based update? What if you need OR in the WHERE (or IN)?
What you really need is a conventional query where only SET statement values have to be generated.
So, you need a helper function to produce such a statement out of data array, returning both correctly formatted SET statement and array with variables to be bound:
$fields = array("name","email");
$sql = "UPDATE users SET ".pdoSet($fields,$values,$data)." WHERE id = :id"
// now we have $values array to be passed into query
$stmt = $dbh->prepare();
$values["id"] = $_POST['id'];
$stmt->execute($values);
With this code you'll be able to make updates for the arbitrary query. And make it safe.
As a further step you will need to start using type-hinted placeholders, to make whole code like this:
$db->query("UPDATE ?n SET ?u WHERE id IN(?a)",$table,$data,$ids);
Getting back to your problem, ONe is right - you need to use bindValue instead of bindParam (as it mentioned in the tag wiki)
I believe the problem is that you are using a foreach to bind the params to the query. Why is this a problem? Because when you bind a variable, you bind a reference to that variable, so if that variable changes, the value in the query will change too. Since you are using a foreach loop, the value for all the parameters will be the latest value that the variable $value referenced to.
You can read more about this foreach behavior here and here. So basically, you have 2 options:
Use a reference to the actual value, instead of using a reference to $value (which can change its value in the next iteration)
Use an auxiliar variable that references another memory position that won't change during the loop
I came here because I was having the same problems, and YCS's solution was what I needed. For anyone else in this situation, here's the helper function I ended up using:
function commit_table($record_id, $changed_values)
{
$db = open_database();
$query = 'UPDATE table SET ';
$query_arguments = array();
$is_first = TRUE;
foreach(array_keys($changed_values) as $key)
{
if($is_first)
{
$is_first = FALSE;
}
else
{
$query .= ', ';
}
$value_var = ':' . $key;
$query .= $key;
$query .= ' = ';
$query .= $value_var;
$query_arguments[$value_var] = $changed_values[$key];
}
$query .= ' WHERE record_id = :record_id';
$query_arguments[':record_id'] = $record_id;
$stmt = $db->prepare($query);
$stmt->execute($query_arguments);
close_database($db);
}

Categories