I have a PDO update query gets the $_POST (or any other key-value array) and writes up the UPDATE query in respect to the inputs given.
I have an exclude array that I can specify keys to not include in the SQL query, such as the submit key and value of the form (action_update_survey, in this case.).
I create the SQL query by iterating through the array via foreach to firstly create the query and insert the parameter placeholders and secondly to bind the parameters to the parameter placeholder within the query.
Here is my code:
function save_survey($post){
global $pdo;
$exclude_names = array('action_update_survey');
$wp_userid = get_current_user_id();
$update_survey_query = "UPDATE kwc_surveysessions SET ";
foreach($post as $key=>$value){
if(!in_array($key, $exclude_names)) $update_survey_query .= $key." = :".$key.", ";
}
$update_survey_query = rtrim($update_survey_query, ", ")." WHERE wp_userid=:wp_userid";
$update_survey = $pdo->prepare($update_survey_query);
print_r($update_survey_query);
foreach($post as $key=>$value){
if(!in_array($key, $exclude_names)){
$update_survey->bindParam($key, $value);
}
}
$update_survey->bindParam("wp_userid", $wp_userid);
$update_survey->execute();
}
After executing my function following a post, all text columns in my database are set to the value 'Save', which is the value of the submit input, of name *action_update_survey*, which is strange, because it should be excluded from both foreach loops, which assign the keys and values.
Printing the PDO query before executing shows that there's been no setting of the excluded input anywhere in my query:
UPDATE kwc_surveysessions SET s1q1 = :s1q1, s1q2 = :s1q2, s1q7 = :s1q7, s1q8 = :s1q8, s1q9 = :s1q9, s1q10 = :s1q10, s1q11 = :s1q11, s2q6 = :s2q6, s3q7 = :s3q7 WHERE wp_userid=:wp_userid
Any idea what would be causing the submit input to push its value into all my fields?
The most probable cause is that bindParam() passes values by refference.
Try using an array like this:
arr = array();
foreach($post as $key=>$value){
if(!in_array($key, $exclude_names)){
arr[$key] = $value;
}
}
$update_survey->execute($arr);
and use "arr" to execute the query.
Related
I'm gonna try to be as clear as possible.
I'm currently working on a project for my work, with dynamic forms where the form inputs are in a database, and created dynamically. Every input row looks something like:
Question? Radiogroup Textinput
And when the user press submit in a section of maybe 3-5 of these rows the form is serialised and managed with AJAX. So here comes the part I'm having trouble with, as of now, in my AJAX file, there is a foreach loop which loops through all $_POST values, adds them to an array and then after the array is complete all data is inserted to a SQL database. And I don't know if it's a problem since I'm not a professional DBA, but there's a lot of rows being inserted to the database, since EVERY radio group, and EVERY text input, gets their own row. And I was thinking if I at least could cut it down to every question getting their own row, but how do I then merge the radio group value with the text input value so they are on the same row but different columns.
I hope I'm being clear enough here.
Database layout today
|ID|RowID|Type|User|Value
Where Type is either Radio or Text. What I want to achieve to get half of the rows I'm gonna get this way is:
|ID|RowID|Type|User|Radio|Text
And the problem is howto achieve this when my foreach loop fills an array with a lot of rows, for each form, which as I say, is containing maybe 3-5 rows with both a radio group and a text input. This is how I do it today:
foreach($_POST as $key => $value) {
$values[] = "'{$id}', '{$user}', '{$type}', '{$value}'";
}
$mysqli->query('INSERT INTO data (rowid, user, type, value) VALUES ('.implode('),(', $values).')');
Hope someone can help me out.
Best Regards
Cisco
Solved it by doing the following:
//Only define for testing.
$_POST['rad_1'] = "yes";
$_POST['rad_2'] = "no";
$_POST['rad_3'] = "yes";
$_POST['txt_1'] = "Test";
$_POST['txt_2'] = "Test2";
$_POST['txt_3'] = "Test3";
$array = array();
foreach($_POST as $key => $value) {
$keyarr = explode('_', $key);
$type = $keyarr[0];
$id = $keyarr[1];
$value = $value;
$array[$id][$type] = $value;
}
$values = array();
foreach($array as $key => $value)
{
$values[] = implode(', ', $value);
}
$query = "INSERT INTO table_name test VALUES (" . implode ("),(", $values) . ")";
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
I want to update my database inside the foreach statement but it gives me the same values that I insert on to the last value that I input.
Let's say I have a looping textbox at the previous page.
$i = 0;
while($row_recordset = mysql_fetch_array($query_run))
{
echo "<tr>";
<td'><input type='text' name='atten_ave".$i."''></td>
echo "</tr>";
$i++;
}
Now this code will get each value of the textbox and should be update the database from the previous page.
foreach($_POST as $textbox => $values) {
$sessionbatch = getbatchno('BATCHNO');
$query_update = "UPDATE `grades`
SET
`ATTEN_SUM` = '$values'
WHERE
`BATCHNO` = '$sessionbatch'
";
if(mysql_query($query_update)){
echo 'SUCCESS';
} else{
die(mysql_error());
}
when I check my ATTEN_SUM COLUMN the values are the SAME base on the last input on the textbox.
First off, do not loop through every value in $_POST. Give your textboxes an idenitcal name that has [] appended to it, like name="atten_ave[]". This will create an array for them within $_POST, then you can loop through them all safely with:
foreach($_POST["atten_ave"] as $textbox => $values) { ....
Now whenever getbatchno('BATCHNO'); returns a value it has already returned within the life of that loop, it will overwrite the update it previously did with that similar value. So if it is returning the same value in every iteration, your query will just keep overwriting itself.
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);
}
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!