I'm trying to create a PHP script that takes based on which input fields are filled in out of the total, uses those fields as SQL parameter to create a SQL query. But if none of the fields are filled out, then query would just retrieve all data.
Example: if fields "Name" and "City" are entered, then the query will have to concatenate "AND name = X_INPUT AND city = Y_INPUT" at the end.
I tried to instantiate $POST variables for the sake of testing but returns nothing. I'm not even sure if this is the best way to tackle the problem but any help would be greatly appreciated!
$_POST['name']="Linda";
$_POST['city']="";
$query = "select * from customers where gender = 'F'";
if (empty($_POST)) {
$query = "select * from customers where gender ='F'";
}
else{
foreach($_POST as $key => $v) {
if (!empty($_POST[$key])) {
$cond = " and ".$key."='".$v."'";
$query = $query.$cond;
The code:
$query = $query.$cond;
every appends unnecessary query to the SQL. Get all your conditions in an array and simple concatenate them as a string. Everything should work this way.
$conditions = array();
foreach($POST as $key => $v) {
if (!empty($_POST[$key])) {
$conditions = " $key = '$v'";
}
}
if (! empty($conditions)) {
$sql .= implode(' AND ', $conditions);
}
You have a typo in your foreach loop, Use this
$_POST
instead of
$POST
Related
I am trying to pass a array in sql query.
Array contains coloumn names as index they are assigned to their respective values which i got using GET method.
for example iam trying to compile this code :
$a='email';
$b=array($a => $_GET['x']);
$sql="SELECT * FROM users WHERE $b";
echo $sql;
The output that i need is:
SELECT * FROM users WHERE email='/*value of $_GET['x']*/'
the output that i am getting is:
SELECT * FROM users where Array
can some one help me how to make it work.
You need to manipulate the $b array to make it into the string your after, at the moment it's just dumping the content in it's own format.
This version will do what your after...
$b=array($a => $_GET['x']);
$columns = [];
foreach ( $b as $name => $value ) {
$columns[] = "$name = '$value'";
}
$sql="SELECT * FROM users WHERE ".implode(" and ", $columns);
echo $sql.PHP_EOL;
I've made it use and as the condition linking multiple columns, you can change this depending on your requirement.
This version instead uses bind parameters, the place holder is inserted instead of the value in the query and then you will need to bind the $data array to the prepared statement (how depends in the API your using). This is safer and more flexible (and recommended)...
$b=array($a => $_GET['x']);
$columns = [];
$data = [];
foreach ( $b as $name => $value ) {
$columns[] = "$name = ?";
$data[] = $value;
}
$sql="SELECT * FROM users WHERE ".implode(" and ", $columns);
echo $sql.PHP_EOL;
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);
}
This question already has answers here:
Passing an array to a query using a WHERE clause
(17 answers)
Closed 1 year ago.
Hi I'm trying to compare values from 2 arrays with this query, which is the only way I know:
$session = "1,2,3,"
$table_name = "table1";
$column_name = "data1"; // value for test is 1,4,5,
$sql = "";
$sql .= "SELECT * FROM $table_name WHERE ";
$franquia = array();
$franquia = explode(",", $session);
if (!empty($franquia)) {
$final_id = array();
foreach ($franquia as $val) {
if (trim($val) != '') {
$final_id[] = $val;
}
}
$count_data = count($final_id);
foreach ($final_id as $key => $id) {
if ($id > 0) {
$sql .= " $id IN ($column_name) ";
if ($key < $count_data - 1) {
$sql .= "OR ";
}
}
}
}
echo $sql;
I have values 1,2,3 on $session and 1,4,5on $data1 so the comparison between $session and $data1 was suposed to return true due to both of them have value 1, but I don't get any results.
Actually it only works if both arrays are the same, like $session = 1,2,3 and $data1 = 1,2,3
What am I doing wrong?
You are using the IN clause wrong; In a nutshell, instead of
WHERE value IN (column)
The correct usage is:
WHERE column IN (value, value, value)
Which in turn will not help with what you are trying to do (more about the IN clause). Rather, try the following:
foreach ($final_id as $key => $id) {
if ($id > 0) {
$sql .= "$column_name LIKE %$id,%";
if ($key < $count_data - 1) {
$sql .= "OR ";
}
}
}
}
This should work, but there are a couple things you should be aware of. First you probably are vulnerable to SQL Injections, and second you should consider either using a different scheme with your data in your DB, since using LIKE %% to search for numeric values is a waste, or fetch in advance the entry from the DB and search in the resulting string. Consider the code above nothing but a quick and dirty hack that you should rather avoid :)
I have an odd issue. I have one PHP script that is used for multiple forms. It takes in all the requests and then puts the data in the appropriate table in a database. As it stands, it looks like this:
$fields = "";
$values = "";
foreach ($_REQUEST as $key=>$value)
{
$key = str_replace(":","",$key);
$fields .= "$key,";
$values .= "'$value ',";
}
//remove the ending comma from $fields and $values
$fields = substr($fields, 0, -1);
$values = substr($values, 0, -1);
$sql = "INSERT INTO " . $survey . " ($fields) VALUES ($values)";
mysql_query($sql)
or die(mysql_error());
And this works well. The problem is, there are some forms with checkboxes (i.e. a person can select more than one option). If I were to use a get method, the query string would look like:
www.somesite.php?V9=1&V9=2&V9=4
With the current script, only 4 is taken, since it was the last value.
Now, I know a reason this is happening is because of the way the name of the checkbox is defined in the form. It says name="V9" instead of name="V9[]" However, I cannot change the forms. They are generated by software, and the idea is that any user can create an HTML form, point it to the script and their information will be recorded in a table. So, changing the HTML is not an option for me.
So, I need a way to detect whether a key has been submitted, and if so, append the value. I tried this:
$fields = "";
$values = "";
foreach ($_REQUEST as $key=>$value)
{
//check to see if the key has already been used for multi-choice questions
$key_check = strpos($fields, "$key,");
if($key_check !== false){
$values = substr($values, 0, -2);
$values .= "\;$value ',";
}else{
$key = str_replace(":","",$key);
$fields .= "$key,";
$values .= "'$value ',";
}
}
//remove the ending comma from $fields and $values
$fields = substr($fields, 0, -1);
$values = substr($values, 0, -1);
$sql = "INSERT INTO " . $survey . " ($fields) VALUES ($values)";
mysql_query($sql)
or die(mysql_error());
But I get the same results. $key_check never seems to be valid. Any help would be appreciated. Someone here has a working ASP version that does a similar thing, but it emails the data, rather than saving it in a DB.
You could try this if you are using $_GET:
function convertInput($qs=""){
$rtn = "";
$holdingArray = array();
if(trim($qs)!=""){
$vars = explode("&", $qs);
foreach($vars as $val){
$kv = explode("=", $val);
if(count($kv)==2){
if(isset($holdingArray[$kv[0]])){
$holdingArray[$kv[0]] .= "," . $kv[1];
}else{
$holdingArray[$kv[0]] = $kv[1];
}
}
}
$rtn = $holdingArray;
}
return $rtn;
}
print_r(convertInput($_SERVER["QUERY_STRING"]));
Try this:
$keys = array();
$values = array();
foreach ($_POST as $key=>$value){ //So, it will loop through the form data
if (!array_search($key, $keys)){ //Checking to see if the key has been used yet
$keys[] = $key;
} else {
$values[$key][] = array($key=>$value);
}
}
This should build an array of your FORM SELECT choices built from the same form, provided that the data is preserved from the browser and is logically eliminated (when accessed as an array, only the last element of the same associated key is preserved, but otherwise the data is there to be had) instead of procedurally eliminated.
I have no idea if this works, because this is building from a theory, not from any kind of documentation or code expertise.
PHP parses the request string (query string or x-www-form-urlencoded) into $_GET, $_POST, and $_REQUEST arrays using the rule that when the same key is present multiple times, later key values overwrite previous ones. So if you cannot change the key names on the forms to append [] like PHP expects, you have to access the raw query string and parse it by hand.
Note that repeating the key name without [] creates ambiguity as to whether a query string key is meant to be a scalar or an array. You will have to decide how to resolve that. E.g., you can use a server-defined hardcoded list of names with array values.
This is how you could process a query string into a list of values:
function paramlist($querystring, $raw=false) {
$plist = array();
$decoder = ($raw) ? 'rawurldecode' : 'urldecode';
$pairs = explode('&', $querystring);
foreach ($pairs as $pair) {
$plist[] = array_map($decoder, explode('=', $pair, 2));
}
return $plist;
}
If you have a query string like a=1&b=2&a=3, this function will return array(array('a','1'),array('b','2'),array('a','3')). You can then turn that to an associative array using any logic you want.
However, you need to get the query or form string in the first place:
if ($_SERVER['REQUEST_METHOD']==='POST'
and $_SERVER['CONTENT_TYPE']==='application/x-www-form-urlencoded') {
// form body
$qs = trim(file_get_contents('php://input'));
} else {
// url query string
$qs = $_SERVER['QUERY_STRING'];
}
Note that if you send a form encoded with multipart/form-data, PHP will not let you access the raw request (even php://input will not work), so in this case there is no way to reprocess the form variables. Sorry!
i have the following code part in one of my classes:
$l = new Location();
$result = $l->getLocIdsbyCity($city); // returns csv
$ids = explode(',', $result);
$where = 'LOC_ID = ' . $ids[0];
unset($ids[0]);
foreach ($ids as $id) {
$where .= ' OR LOC_ID = ' . $id;
}
$select->where($where);
Is there an more "elegant" way to build the select stmt? I need all records with one of the provided ids..
Assuming your csv is injection safe (contains trusted values and no user-provided input):
$l = new Location();
$result = $l->getLocIdsbyCity($city); // returns csv
$where = "LOC_ID IN ($result)";
$select->where($where);
If it's not, you should explode it, mysql_real_escape_string each value and implode back.
You can use the in operator to form a condition like:
where LOC_ID in (1,2,3,4,5)
If you are sure that $result can't contain anything harmful, you should be able to use it directly without having to split it and loop.