Create update query for dynamic database - php

I am trying to update a row in a mysql database. To do this, I would use a simple query like this:
"UPDATE `contactinfo` SET `Company` = 'Google', WHERE `id` = '1';"
The problem is that the database is dynamic and users can add columns at any time. So I do not know the names of the columns. To find the names and create a form to post to the page that will actually do the mysql work uses this code:
<?php
$result = mysql_query("select * from contactinfo WHERE `id` = '".$rid."';");
if (!$result) {
die('Query failed: ' . mysql_error());
}
$i = 0;
while ($i < mysql_num_fields($result)) {
$meta = mysql_fetch_field($result, $i);
if (!$meta) {
echo "ERROR";
}
$name = $meta->name;
$r = mysql_fetch_array(mysql_query("select * from contactinfo WHERE `id` = '".$rid."';"));
$content = $r[$name];
if($name != 'id') {
echo "<tr><td align='center'><div align='left'>Edit ".$name."</div></td></tr>";
echo "<tr><td align='center'><input type='text' value='" . $content . "' /></td></tr>";
}
$i++;
}
mysql_free_result($result);
?>
This creates a nice little table with input boxes that allow the user to edit the content of the row that has been selected. The row id number($rid) is used to identify which row needs to be changed.
My question is, how can I get the new content for the row from the posted form and create a query to update it? I can't seem to figure out how to dynamically get the names of the form as well as the new content to the write the query.
If any clarification is needed just let me know and all help is appreciated.
Thanks.

The easiest way is to name the fields in the form exactly how the name of the fields in the database are.
Lets say you have this form
<form action="">
<input name="field[firstname]">
<input name="field[lastname]">
<input name="field[address]">
</form>
You should probably be able to create the form based on the fields names too, you are probably already doing this.
In the file that processes the response you can do something like this:
foreach($_POST['field'] as $field_name => $field_value) {
$sql_str[] = "{$field_name} = '{$field_value}'";
}
This just goes through the 'field' array that comes from post and puts the proper update text into another array.
Then just do a
mysql_query("UPDATE contactinfo SET ".implode(',', $sql_str)." WHERE `id` = '".$rid."';")
To put it into the database.

What you can do is add a column in the database with a bit flag and if the user is new or old, the flag will reflect it.
that way you can update the user to say if it is new or old.
hope this helps.

You might do well to investigate whether there is an ORM framework that you could use.
Anyway, the simplest way to do what you want is to pass the name of the field in the INPUT field.
$content = AddSlashes($content); // You may need HTMLEntities() here
$field = <<<FIELD
<input type="text" value="$content" />
FIELD;
Also, another useful trick to employ is to either supply an array of "protected" fields, or specify a prefix that makes the field unchangeable. For example, you almost certainly do not want a user to be able to change the primary keys.
So you could generate the form with
if ('id' == $meta->name or 'pk' == $meta->name or (0 === strpos($meta->name, 'pk_')))
{
// This is a primary key field
$html .= <<<PKFIELD
<input type="hidden" name="{$meta->name}" value="{$contents}" />
PKFIELD;
continue;
}
if (0 === strpos($meta->name, 'hf_'))
{
// hidden field, ignored (can't be changed)
continue;
}
if (0 === strpos($meta->name, 'ro_'))
{
// read-only field, shown but without even the name
$html .= <<<ROFIELD
<input type="text" readonly="readonly" class="readonly" value="{$contents}" />
ROFIELD;
continue;
}
Or you could use a fixed-size prefix and an array of templates:
$fieldtpls = array(
'pk_' => '<input type="hidden" name="{NAME}" value="{VALUE}" />',
'ta_' => '<textarea name="{NAME}">{VALUE}</textarea>',
'ro_' => '<input type="text" value="{VALUE}" readonly="readonly" />',
);
then you analyze each field and apply a default unless a known prefix is used.
Your users would then have to name the fields accordingly. Another possibility is to allow for a "meta-table" to hold the type and handling of each table and field, but in that case you would need to complicate a bit the user interface by creating a sort of "admin editor" for the Meta table:
table field type rw parameters
users name text yes
users id hidden no
users role text no
users notes area yes class:"widearea"
...and that way be dragons ORM frameworks.

Related

Define HTML check boxes from database values

I have project with HTML PHP and SQL database. I designed HTML input form to collect data from user and put drop down menu using PHP. It collected data from SQL database using query and those data used to drop down list and user can select those data. I have using following codes in PHP section.
$query2 = "SELECT Name FROM class ORDER BY Name";
$results2 = mysqli_query($connection, $query2);
while($result = mysqli_fetch_array($results2))
{
$Classes .= "<option value=\"{$result['Name']}\">{$result['Name']}</option>";
}
In my database there are several classes as Class_A, Class_B, Class_C and etc. (Admin can create new class or delete available class. Then when user select classes, showing classes can be different according to Admin's settings.)
In HTML form section I used following code to display Class names.
<p>
<label for=" ">Classes Are</label><br>
<select name="Classes[]" size="3" multiple >
<?php echo $Classes ?>
</select>
</p>
I tried to use this process through Check boxes (replace Drop down list from Check boxes) But I cant fix that. So, If someone can give proper way to do this it is highly appreciate.
Perhaps this is what you need to use checkboxes? The name assigned to the HTML input element uses an array type syntax with the name of from the db supplied
$sql = "select `name` from `class` order by `name`";
$res = $connection->query( $sql );
while( $rs = res->fetch_object() ) {
$classes=sprintf(
'<label>%1$s:
<input type="checkbox" value="%1$s" name="Classes[%1$s]" />
</label>',
$rs->name
);
}
Then, to process the form submission once the user has selected one or more checkboxes you could do:
foreach( $_POST['Classes'] as $index => $value ){
// do things...
}
You likely do not even need to add the name so perhaps simply Classes[] as the input name would suffice. Please clarify the issue you had when trying to use checkboxes rather than select menus.

How to update several fields in a single foreach loop?

I have a table with a list of users. Each one has assigned a checkbox. When the admin select some checkboxes my script saves some information into the database for the selected users.
Now, my issue is that beside that checkbox I want to have a text input type so the admin can leave a comment as well for that user. So, when the checkbox is selected and the input type has some data, the data gets saved as well.
This is what I've done so far (besides the obvious issues with security, that I haven't taken into account yet):
My list is generated by a loop for each user:
<input type=text name="infoAdicional" value="'.$x['infoAdicional'].'">
<input name="enviar['.$x['userID'].']" type="checkbox" value="'.$x['userEmail'].'">
I've taken the information and generated a foreach loop for the checkbox, but cannot get the additional information from the text field to get saved (it does update other values:
$userID = $_POST['enviar'];
$infoAdicional = $_POST['infoAdicional'];
foreach ($userID as $id => $email) {
$sql = "UPDATE cursosUsuarios
SET estadoCertificado = 'pending',
infoAdicional='$infoAdicional'
WHERE userID = '$id'
AND email = '$email'
";
...
}
I think that's because $infoAdicional = $_POST['infoAdicional']; should be inside the loop, but just inserting it inside it, gets every user with a selected checkbox to have the same additional information, it does repeat itself.
It doesn't matter if you put the variable $infoAdicional inside the loop or not. The thing is that the last input field with the name overwrites all and therefore you will only have the note of the last user for all. What you need to change is, to make usage of the [] name syntax as you did it with the checkbox.
So your name attribute of the notes field would look like this name="infoAdicional['.$x['userID'].']" and in the loop you would make the assignment of infoAdicional[USERID] to $infoAdicional.
So your code would look like this
$userID = $_POST['enviar'];
foreach ($userID as $id => $email) {
$infoAdicional = $_POST['infoAdicional'][$id];
$sql = "UPDATE cursosUsuarios
SET estadoCertificado = 'pending',
infoAdicional='$infoAdicional'
WHERE userID = '$id'
AND email = '$email'
";
...
}
And your HTML code
<input type=text name="infoAdicional['.$x['userID'].']" value="'.$x['infoAdicional'].'">
<input name="enviar['.$x['userID'].']" type="checkbox" value="'.$x['userEmail'].'">
Change your input parameters to:
<input type=text name="enviar['.$x['userID'].']['infoAdicional']" value="'.$x['infoAdicional'].'">
<input name="enviar['.$x['userID'].']['email']" type="checkbox" value="'.$x['userEmail'].'">
So your data will stick to specific user. Then your loop will be like this:
$userInfo = $_POST['enviar']; //Info here, right?
foreach ($userInfo as $userId => $info) {
$sql = "UPDATE cursosUsuarios
SET estadoCertificado = 'pending',
infoAdicional='$info['infoAdicional']'
WHERE userID = '$userId '
AND email = '$info['email']'
";
...
}
I've saved your syntax as it's your job to fill it with prepared statements etc.

Adding and updating Mysql child table with multiple number of entries

I have two tables in mysql: a master table called "grants" and a child table called "goals". Grants has an id field as well as a bunch of others and goals has a goal name and a grant_id to link it to the grants table.
On the html form, the user can add or edit as many goals as they wish (I'm using Javascript to add new inputs). The form also gets any previous goals added and adds them to the form.
<div id="goals">
<?php
$goals = getGoalsById($_GET['id']);
if (empty($goals)) echo "<p>Goal 1: <input type='text' size='40' name='goals[]' /></p>";
else {
$i = 1;
foreach($goals as $goal) {
echo "<p>Goal {$i}: <input type='text' size='40' name=\"goals[{$goal['id']}]\" value=\"{$goal['goal']}\" /></p>";
$i++;
}
}
?>
</div>
<input type="button" value="Add goal" onClick="addInput('goals')" />
When I submit the form, I have the following statement to insert or update the goals:
foreach($goals as $key=>$goal) {
$sql_goals_add[] = "INSERT INTO goals (id, goal, grant_id) VALUES ($key,:goalnew,$grant_id) ON DUPLICATE KEY UPDATE goal = :goalupdate";
foreach ($sql_goals_add AS $sql_goal) {
$stmt_goal = $DBH->prepare($sql_goal);
$stmt_goal->bindValue(':goalnew', $goal, PDO::PARAM_STR);
$stmt_goal->bindValue(':goalupdate', $goal, PDO::PARAM_STR);
}
$stmt_goal->execute();
}
This works fine for updating existing goals as the key that is passed is the id that is in the goal table. However, the problem I run into is when they have new goals, the $goals array that gets passed from the form always starts at 0 and therefore the insert query tries to use 0, 1, 2, etc as the insert id. I'd rather have it automatically choose the next available id in the goals table.
I have tried to auto-populate what I think could be the new goal id's, but this is a bad idea as multiple people may hit the site as once and it could overlap. Any help is appreciated!
I’m going to make a few assumptions for this process to work for you.
The form in the case of a new entry is blank .
In the case of an update the form is populated from the database as
it stands.
On update the form is redisplayed from the database with a note at
the top that says the update has happened.
This is not bank data or hyper critical fault intolerant data. Which
for your application I don’t think it is. It is a form for
processing administrative data.
The Post process I suggest is a follows.
I suggest split up your insert process a little.
Insert/update into the master table. If it is an insert, grab the record Id from the crated row for use as your external key for the goals table.
Delete all entries from your goals table related to the external key. This will run even if there is no entry yet and will clear all goals should there be any. Literally rip out all rows and do a fresh insert.
Loop through the goals part of the post array using the master table’s record id as the external key for insertion. It is damn hard to keep track of the original goal record IDs for update. Because you cleared the table you don't worry with it as that data is in the post also. If the person edits the wording of a goal you don’t need to detect that to see if the goal needs updating as they are all reentered at once.
Display the form again with data pulled from the database. If there is an error and you output the result back into the form the user can always update again if there is a fault in the update process after the data is cleared from the goals table. The user will see the problem and try again if data is lost.
Again not how I handle bank data but for the form with an infinite number of goals that can be tacked on this is the easiest solution I have found.
Best of luck
So, after having the discussion over in G+, I ended up splitting things out:
1) Rename the arrays that are passed to goalsNew and goalsExisting
2) Changing the function to parse each array separately so it will perform an insert on new entries, but an update on existing entries. Below is the completed code, in case anyone cares. :)
<div id="goals">
<?php
$goals = getGoalsById($_GET['id']);
if (empty($goals)) echo "<p>Goal 1: <input type='text' size='40' name='goalsNew[]' /></p>";
else {
$i = 1;
foreach($goals as $goal) {
echo "<p>Goal {$i}: <input type='text' size='40' name=\"goalsExisting[{$goal['id']}]\" value=\"{$goal['goal']}\" /></p>";
$i++;
}
}
?>
</div>
And here is the function that does it all (and I renamed it dealingWithChildren from dealingWithGoals because this is going to be used for multiple child tables, but also because a new father should have a function called dealingWithChildren!
function dealWithChildren($childType, $childNew, $childExisting, $grant_id) {
$fieldName = substr($childType, 0, -1);
dbConnect();
global $DBH;
try {
// If there are no children at all, delete them all
if(empty($childNew) && empty($childExisting)) {
$sql_child_delete = "DELETE FROM $childType WHERE grant_id = $grant_id";
$stmt_child = $DBH->prepare($sql_child_delete);
$stmt_child->execute();
}
// If the user removed a child, delete those children
if(!empty($childExisting)) {
$sql_child_delete = "DELETE FROM $childType WHERE grant_id = $grant_id AND id NOT IN (";
$i = 0;
$len = sizeof($childExisting);
foreach($childExisting as $key=>$child) {
$sql_child_delete .= $key;
if ($len > 1 && $i < $len-1) $sql_child_delete .= ",";
$i++;
}
$sql_child_delete .= ")";
$stmt_del_child = $DBH->prepare($sql_child_delete);
$stmt_del_child->execute();
}
// If a user added any children
if(!empty($childNew)) {
foreach($childNew as $key=>$child) {
$sql_child_add[] = "INSERT INTO $childType ($fieldName, grant_id) VALUES (:childnew,$grant_id)";
foreach ($sql_child_add AS $sql_child) {
$stmt_child = $DBH->prepare($sql_child);
$stmt_child->bindValue(':childnew', $child, PDO::PARAM_STR);
}
$stmt_child->execute();
}
}
// If a user updated any children
if(!empty($childExisting)) {
foreach($childExisting as $key=>$child) {
$sql_child_update[] = "UPDATE $childType SET $fieldName = :childupdate WHERE id = $key";
foreach ($sql_child_update AS $sql_child) {
$stmt_child = $DBH->prepare($sql_child);
$stmt_child->bindValue(':childupdate', $child, PDO::PARAM_STR);
}
$stmt_child->execute();
}
}
} catch (PDOException $f) {
echo 'Database query failure: ' . $f->getMessage();
//exit;
}
dbDisconnect();
}

Processing a form created by dynamic php/mySql Setup

I run a script to create an order form, this is just a really small sample. I'm not so good with PHP and dynamic forms. It pulls data from mysql database.
<td>
<h3>Round Cuts</h3>
<?php while($row = mysql_fetch_array($round_cuts)){
$round_box_value = #$row["meat_names"];
$round_box_value_name = #$row["meat_names"];
echo " <input type=\"checkbox\" name=\"round_box_value\" value=\"$round_box_value_name\"> $round_box_value_name";
echo "<br>";
}?>
</td>
I've ever really only built basic contact forms, how could I process a dynamic form like this. If all else fails I would just take all the possible elements and program this like it was a not dynamic. There must be a better way though.
Even a link to a website would be helpful. I've been searching for a solution. Thanks.
I'll assume your table as a primary key of id
Start off with a minor change to your checkboxes:
<?php
while($row = mysql_fetch_array($round_cuts)){
echo sprintf('<label><input type="checkbox" name="round_box_value[]" value="%s"> %s</label><br>', $row['id'], $row['meat_names']);
}
?>
The name now has an [] at the end to tell php it's an array of values + I've wrapped the checkbox in a label for convenience.
Then when you process the form, you can simply iterate through round_box_value like so
<?php
foreach ($_POST['round_box_value'] as $id) {
// $id is the table reference from your previous table
}
// or query all the rows selected
$ids = array_map('intval', $_POST['round_box_value']); // "basic" sql injection handler
$sql = "SELECT * FROM table WHERE id IN (".implode(",", $ids).")";
should produce something like:
SELECT * FROM table WHERE id IN (2,5,7)

Updating multiple records in mySQL table via PHP web form table?

Need a little help...
I have a basic html table with text field form in last column and a hidden field on each row of the web table. The data in this table is extracted out of a table in the database.
I want my users to be able to update one field in the database (a score) using this web form (page).
I have a hidden web form component on each row that contains the unique id of the record in the database for each row in the web page table.
I was attempting to create code that would update the entire list of entries on the web form, even if the user is not updating that particular field. (The values of the scores field are populated into the web form at the creation of the table. So if you did not update any scores, but hit the submit button, it would update the database table with the same values.)
Here’s my code: (abbreviated to save bytes…)
<?php
//Do all the database connection stuff up front
if (isset($_POST[‘score’]))
{
$student_id = $_POST[‘student_id’];
$score = $_POST['score'];
$n = count($score);
$i = 0;
echo "You have updated these student scores on this assignment. \r\n" .
"<ol>";
while ($i < $n)
{
echo "<hr><P>{$score[$i]} \r\n";
echo "<hr><P>{$student_id[$i]} \r\n";
$qry = "UPDATE assignments SET score = ".$score[$i]." WHERE student_id = " .$student_id[$i]. '"';
$result=#mysql_query($qry);
$i++;
}
}
if($result) {
header("location: member-index.php");
exit();
}else {
die("Query failed");
}
?>
Am I on the right track? Is there a better way to do what I’m attempting? All suggestions and ideas welcome!
Thank you in advance!
i'm guessing you are using
<input name="scores[]"/>
why not echo the unique id into the input name?
<input name="score[<?php echo $unique_id ?>]" />
this means in the loop, the $i would be the unique id (one less variable and less HTML).
and please use mysql_real_escape_string() when working with DB transactions. I know it's an example code but please don't forget that
Besides that, yes, you are on the right track

Categories