I have an application that looks like this:
As you can see, each row contains either a group heading (the rows where there is just an input), or a ingredient form (where there is a small input, then a select, then another larger input).
I use Javascript to add the new spans. I use the following PHP to group each ingredient span into an array, determine the order (because each span can be moved to a different order), and insert into my database.
foreach($_POST as $key => $value) {
$value = $this->input->post($key);
$ingredientQTY = $this->input->post('ingredientQTY');
$measurements = $this->input->post('measurements');
$ingredientNAME = $this->input->post('ingredientNAME');
$ingredientsROW[] = array($ingredientQTY, $measurements, $ingredientNAME);
for ($i = 0, $count = count($ingredientQTY); $i < $count; $i++) {
$rows[] = array(
'ingredientamount' => $ingredientQTY[$i],
'ingredientType' => $measurements[$i],
'ingredientname' => $ingredientNAME[$i],
'recipe_id' => $recipe_id,
'order' => $i + 1,
'user_id' => $user_id
);
$sql = "INSERT `ingredients` (`ingredientamount`,`ingredientType`,`ingredientname`, `recipe_id`, `order`, `user_id`) VALUES ";
$coma = '';
foreach ($rows as $oneRow) {
$sql .= $coma."('".implode("','",$oneRow)."')";
$coma = ', ';
}
}
$this->db->query($sql);
break;
}
This works wonders for inserting the ingredient rows. But I'm not sure how to insert group headings (which must be placed in the for loop to keep the order, the $i + 1, going).
I think I've figured out two solutions(though there may be others, and these might not even work):
Have the group heading input field have the same name value as one of the ingredient text fields, and send a hidden value along with it, saying its a group heading?
Send it as different input field with a different name value?
My question is: how can I do this with my current code, and are either of these efficient solutions, or is there an even better solution?
Thanks for all help! If you need more details, just ask!
You could use an empty heading like <input type="hidden" name="groupheading[]" value="product" /> and the open one like <input type="text" name="groupheading[]" value="" />. The first one should be inside the product-span.
This way, you can continue your loop just the way you are doing now. And $_POST['groupheading'][$key] either returns a groupheading or the phrase 'product'. So, in your script it would be:
if($_POST['groupheading'][$key] == "product") {
// insert product
} else {
// insert group heading
}
I think I helped you this morning or yesterday with an answer.. it's still a bit a weird way you are using to get the effect you need. It can be achieved much easier.
Related
Sorry for the ambiguous title, I don't know how else to name this.
I need to delete specific values in specific quantities from my database. I have a table with some numbers. It looks something like this
1,2(1),3,4,5(6),6(3),7(2),8,9(4),10
The numbers in brackets represent how many times a base number is found in the mysqli database. My form lets me select multiple duplicate numbers and how many duplicates of a number I want to delete. So for example I have selected:
2(1),5(4),9(2)
This is the code that gives me those values but it is imperfect because I receive all the numbers that have at least one duplicate in the database and empty values where there is no number selected and normal numbers when it's selected.
<input type="number" name="quantity[]" id="quantity" min="0" max='<?php echo "$count[$item]"?>' />
input type="hidden" name="hidden[]" id="hidden" value='<?php echo "$item" ?>' />
My thought process is that I needed to build the code so that I knew exactly the number that was selected for the amount of times it is selected. So I wanted to make an associative array from the 2 values that I am supposed to receive. It works, it gives me that information, but I just can't make it delete selected items the number of times that I want, it deletes all the existing duplicates of the selected items.
$arr1 = array();
$arr2 = array();
$newAssoc = array();
if( isset( $_POST['submit'] ) ) {
$quantity = $_POST['quantity'];
$hidden = $_POST['hidden'];
foreach( $hidden as $var1 ) {
$arr1[] = $var1;
}
foreach( $quantity as $var2 ) {
$arr2[] = $var2;
}
$newAssoc = array_combine( $arr1, $arr2 );
foreach( $newAssoc as $key => $val ) {
if( !empty($val)) {
$i = 1;
while( $i <= $val ) {
$delete = mysqli_query( $db, "DELETE FROM duplicates
WHERE numbers=$key" );
++$i;
}
}
}
}
I've tried quite a few things and I'm in a bit of a pickle because nothing worked and I'm out of ideas.
EXPECTED RESULT: I will repeat myself, I need to delete specific values in specific quantities from my database.
Sorry for the wall of text and horrendous code/coding practice/coding logic, still a bit new to both coding and stackoverflow.
Thank you for your help RiggsFolly, your answer has fixed all my problems. If anyone has anything interesting to add I don't mind. Thank you !
This is the portion of the code that was changed in order for my expected result to be fullfiled, if anyone needs it:
foreach( $newAssoc as $key => $val ) {
if( !empty($val)) {
$delete = mysqli_query( $db, "DELETE FROM duplicates
WHERE numbers=$key
LIMIT $val" );
}
On single tables, you can limit the number of rows deleted by using limit.
Your query would look something like DELETE FROM table WHERE key=value LIMIT 10. See the official documentation of mysql.
I thought I would edit my question as by the comment it seems this is a very insecure way of doing what I am trying to acheive.
What I want to do is allow the user to import a .csv file but I want them to be able to set the fields they import.
Is there a way of doing this apart from the way I tried to demonstrate in my original question?
Thank you
Daniel
This problem I am having has been driving me mad for weeks now, everything I try that to me should work fails.
Basically I have a database with a bunch of fields in.
In one of my pages I have the following code
$result = mysql_query("SHOW FIELDS FROM my_database.products");
while ($row = mysql_fetch_array($result)) {
$field = $row['Field'];
if ($field == 'product_id' || $field == 'product_name' || $field == 'product_description' || $field == 'product_slug' || $field == 'product_layout') {
} else {
echo '<label class="label_small">'.$field.'</label>
<input type="text" name="'.$field.'" id="input_text_small" />';
}
}
This then echos a list of fields that have the label of the database fields and also includes the database field in the name of the text box.
I then post the results with the following code
$result = mysql_query("SHOW FIELDS FROM affilifeed_1000.products");
$i = 0;
while ($row = mysql_fetch_array($result)) {
$field = $row['Field'];
if ($field == 'product_name' || $field == 'product_description' || $field == 'product_slug' || $field == 'product_layout') {
} else {
$input_field = $field;
$output_field = mysql_real_escape_string($_POST[''.$field.'']);
}
if ($errorcount == 0) {
$insert = "INSERT INTO my_database.products ($input_field)
VALUES ('$output_field')";
$result_insert = mysql_query($insert) or die ("<br>Error in database<b> ".mysql_error()."</b><br>$result_insert");
}
}
if ($result_insert) {
echo '<div class="notification_success">Well done you have sucessfully created your product, you can view it by clicking here</div>';
} else {
echo '<div class="notification_fail">There was a problem creating your product, please try again later...</div>';
}
It posts sucessfully but the problem is that it creates a new "row" for every insert.
For example in row 1 it will post the first value and then the rest will be empty, in row 2 it will post the second value but the rest will be empty, row 3 the third value and so on...
I have tried many many many things to get this working and have researched the foreach loop which I haven't been familiar with before, binding the variable, imploding, exploding but none of them seem to do the trick.
I can kind of understand why it is doing it as it is wrapped in the while loop but if I put it outside of this it only inserts the last value.
Can anyone shed any light as to why this is happening?
If you need any more info please let me know.
Thank you
Daniel
You're treating each field you're displaying as its own record to be inserted. Since you're trying to create a SINGLE record with MULTIPLE fields, you need to build the query dynamically, e.g.
foreach ($_POST as $key => $value);
$fields[] = mysql_real_escape_string($key);
$values[] = "'" . msyql_real_escape_string($value) . "'";
} // build arrays of the form's field/value pairs
$field_str = implode(',', $fields); // turn those arrays into comma-separated strings
$values_str = implode(',', $values);
$sql = "INSERT INTO yourtable ($field_str) VALUES ($value_str);"
// insert those strings into the query
$result = mysql_query($sql) or die(mysql_error());
which will give you
INSERT INTO youtable (field1, field2, ...) VALUES ('value1', 'value2', ...)
Note that I'm using the mysql library here, but you should avoid it. It's deprecated and obsolete. Consider switching to PDO or mysqli before you build any more code that could be totally useless in short order.
On a security basis, you should not be passing the field values directly through the database. Consider the case where you might be doing a user permissions management system. You probably wouldn't want to expose a "is_superuser" field, but your form would allow anyone to give themselves superuser privileges by hacking up their html form and putting a new field saying is_superuser=yes.
This kind of code is downright dangerous, and you should not be using it in a production system, no matter how much sql injection protect you build into it.
Alright....I can't say that I know exactly whats going on but lets try this...
First off....
$result = mysql_query("SHOW FIELDS FROM my_database.products");
$hideArray = array("product_id","product_name","product_description", "product_slug","product_layout");
while ($row = mysql_fetch_array($result)) {
if (!in_array($row['Field'], $hideArray)){
echo '<label class="label_small">'.$field.'</label>
<input type="text" name="'.$field.'" id="input_text_small" />';
}
}
Now, why you would want to post this data makes not sense to me but I am going to ignore that.....whats really strange is you aren't even using the post data...maybe I'm not getting something....I would recommend using a db wrapper class...that way you can just through the post var into....ie. $db->insert($_POST) ....but if you ware doing it long way...
$fields = "";
$values = "";
$query = "INSERT INTO table ";
foreach ($_POST as $key => $data){
$values .= $data.",";
$fields .= $fields.",";
}
substr($values, 0, -1);
substr($fields, 0, -1);
$query .= "(".$fields.") VALUES (".$values.");";
This is untested....you can also look into http://php.net/manual/en/function.implode.php so you don't have to do the loop.
Basically you don't seem to understand what is going on in your script...if you echo the sql statements and you can a better idea of whats going....learn what is happening with your code and then try to understand what the correct approach is. Don't just copy and paste my code.
I have this piece of code that currently almost does what I need. It needs to select all records from a table and then format them ready for encoding to JSON. However, ONE record will have a "type" field set as "default". This record is placed first in the JSON file and formatted slightly different.
Currently this works prefectly if the record set to default is the last entry in the database table. But, if it isn't, then the formatting breaks when encoding to JSON.
Can anyone help suggest a fix that would force it to ignore where the default entry is, but retain the formatting?
// Get the data from the DB.
$query = 'SELECT type, headline, startDate, text, media, caption, credits FROM #__timeline_entries'.$table.'';
$db->setQuery($query);
// Load it and put it into an array
$list = $db->loadObjectList();
$len = count($list);
$data = array();
for ($i = 0; $i < $len; $i++) {
$temp = (array) $list[$i];
$temp["asset"] = array(
"media" => $temp["media"],
"credit" => $temp["credits"],
"caption" => $temp["caption"]
);
unset($temp["media"]);
unset($temp["credits"]);
unset($temp["caption"]);
if ($temp["type"] == "default") {
$data = $list[$i];
unset($list[$i]);
$list[$i] = $temp;
}
}
// Prep it for JSON
$data->date = &$list;
// Loop it once more!
$dataTwo->timeline = &$data;
// Encode the data to JSON.
$jsondata = json_encode($dataTwo);
This is part of a Joomla component, but it doesn't really use any of the Joomla framework beyond the database connection. I thought I'd mention it just in case it made any difference, though I don't see how.
Add an ORDER BY clause:
ORDER by (type = "default")
This will be 0 for all the records except the default, which is 1, so it will be put last.
Add a WHERE clause to your MySQL statement:
$query = 'SELECT type, headline, startDate, text, media, caption, credits FROM #__timeline_entries'.$table.' WHERE type <> default';
Greetings! This is my first question.
I've searched all over the web as well as on SO, but I believe it is too specific for me to find an answer. I'm guessing my code may need a logical rebuild.
Background of problem:
I am building a simple site containing user-editable inventory data (a list of used RVs) for a friend's business. This is basically my first big project with php, well, ever, and I'm on a tight deadline (we're in season right now!), so my code is absolute filth. To add to that, I'm mixing procedural and object-oriented programming like a nutjob.
Explanation of problem:
Some of the data in the MySQL table "rv_list" - namely, the 'status' and the 'condition' fields (see attached screenshot to get a clearer idea), are currently being stored as 1-digit integers.
I thought that it would be very easy to (using php regex or something) later convert these numbers to strings, as they were on the input form. As it turns out, with the method I finally settled on outputting the data, I cannot find a way to convert them after the select statement is done.
Code:
<?php
//unfinished query - "condition" is the column in the db table that I'd like to change, "status" will also need to be changed in a similar way for the outward-facing public-viewed list
$query = 'select * from rv_list where status="1" or status="2" order by modified desc';
$rvfieldquery = 'show columns from rv_list';
$result = $conn->query($query);
//check on the status of our query
if ($result)
{
//begin output of html table, followed by a loop for rows, and within, a nested loop for the datacells.
//based on function 3: http://www.barattalo.it/2010/01/29/10-php-usefull-functions-for-mysqli-improved-stuff/
echo '<table>';
echo '<th>Edit Status</th>';
while ($field = $result->fetch_field())
{
echo '<th class="columntitle">'.$field->name.'</th>';
}
echo '<th>DELETE</th>';
$shadecounter = 0;
while ($row = $result->fetch_assoc())
{
//shade every other row for usability
$shadecounter++;
if (is_float($shadecounter/2)) $shade = "lightgray";
else $shade = "white";
echo '<tr style="background:'.$shade.';">';
//Get rv_id key, attach to name of edit and delete buttons
echo '<td><input type="submit" name="edit '.$row['rv_id'].'" value="Edit"></input></td>';
//Insert row data
foreach ($row as $td)
{
//PROBLEM AREA HERE! - can I do an if statement or something here to check what column $td comes from? Confused.
echo '<td class="data">'.$td.'</td>';
}
//for delete record button, off-screen on right side of each record
echo '<td><input style="background:red;" type="submit" name="del '.$row['rv_id'].'" value="DELETE"></input></td>';
echo '</tr>';
}
echo '</table>';
}
else
{
exit;
}
Output Screenshot (check highlights):
http://i.stack.imgur.com/N8P8r.jpg
Extra Information:
Key to the status integer list (rather, what I would like it to display):
Available
On Hold
Sold / Deactivated
Key to the condition integer list:
New
Used - Excellent
Used - Good
Used - Fair
Used - Poor
Please let me know if I have forgotten anything crucial in describing this problem.
Last but not least, thank you very much for your time spent reading this question!
$status_map = array(1 => 'Available', 2 => 'On Hold', 3 => 'Sold / Deactivated');
$condition_map = array(1 => 'New', 2 => 'Used - Excellent', 3 => 'Used - Good', 4 => 'Used - Fair', 5 => 'Used - Poor');
foreach ($row as $colname => $value)
{
if($colname == 'status')
$value = $status_map[$value];
if($colname == 'condition')
$value = $condition_map[$value];
echo '<td class="data">'.$value.'</td>';
}
I'm trying hard to wrap my head around what I'm doing here, but having some difficulty... Any help or direction would be greatly appreciated.
So I have some values in a table I've extracted according to an array (brilliantly named $array) I've predefined. This is how I did it:
foreach ($array as $value) {
$query = "SELECT * FROM b_table WHERE levelname='$value'";
$result = runquery($query);
$num = mysql_numrows($result);
$i=0;
while ($i < 1) {
$evochance=#mysql_result($result,$i,"evochance"); // These values are integers that will add up to 100. So in one example, $evochance would be 60, 15 and 25 if there were 3 values for the 3 $value that were returned.
$i++;
}
Now I can't figure out where to go from here. $evochance represent percentage chances that are linked to each $value.
Say the the favourable 60% one is selected via some function, it will then insert the $value it's linked with into a different table.
I know it won't help, but the most I came up with was:
if (mt_rand(1,100)<$evochance) {
$valid = "True";
}
else {
$valid = "False";
}
echo "$value chance: $evochance ($valid)<br />\n"; // Added just to see the output.
Well this is obviously not what I'm looking for. And I can't really have a dynamic amount of percentages with this method. Plus, this sometimes outputs a False on both and other times a True on both.
So, I'm an amateur learning the ropes and I've had a go at it. Any direction is welcome.
Thanks =)
**Edit 3 (cleaned up):
#cdburgess I'm sorry for my weak explanations; I'm in the process of trying to grasp this too. Hope you can make sense of it.
Example of what's in my array: $array = array('one', 'two', 'three')
Well let's say there are 3 values in $array like above (Though it won't always be 3 every time this script is run). I'm grabbing all records from a table that contain those values in a specific field (called 'levelname'). Since those values are unique to each record, it will only ever pull as many records as there are values. Now each record in that table has a field called evochance. Within that field is a single number between 1 and 100. The 3 records that I queried earlier (Within a foreach ()) will have evochance numbers that sum up to 100. The function I need decides which record I will use based on the 'evochance' number it contains. If it's 99, then I want that to be used 99% of the time this script is run.
HOWEVER... I don't want a simple weighted chance function for a single number. I want it to select which percentage = true out of n percentages (when n = the number of values in the array). This way, the percentage that returns as true will relate to the levelname so that I can select it (Or at least that's what I'm trying to do).
Also, for clarification: The record that's selected will contain unique information in one of its fields (This is one of the unique values from $array that I queried the table with earlier). I then want to UPDATE another table (a_table) with that value.
So you see, the only thing I can't wrap my head around is the percentage chance selection function... It's quite complicated to me, and I might be going about it in a really round-about way, so if there's an alternative way, I'd surely give it a try.
To the answer I've received: I'm giving that a go now and seeing what I can do. Thanks for your input =)**
I think I understand what you are asking. If I understand correctly, the "percentage chance" is how often the record should be selected. In order to determine that, you must actually track when a record is selected by incrementing a value each time the record is used. There is nothing "random" about what you are doing, so a mt_rand() or rand() function is not in order.
Here is what I suggest, if I understood correctly. I will simplify the code for readability:
<?php
$value = 'one'; // this can be turned into an array and looped through
$query1 = "SELECT sum(times_chosen) FROM `b_table` WHERE `levelname` = '$value'";
$count = /* result from $query1 */
$count = $count + 1; // increment the value for this selection
// get the list of items by order of percentage chance highest to lowest
$query2 = "SELECT id, percentage_chance, times_chosen, name FROM `b_table` WHERE `levelname` = '$value' ORDER BY percentage_chance DESC";
$records = /* results from query 2 */
// percentage_chance INT (.01 to 1) 10% to 100%
foreach($records as $row) {
if(ceil($row['percentage_chance'] * $count) > $row['times_chosen']) {
// chose this record to use and increment times_chosen
$selected_record = $row['name'];
$update_query = "UPDATE `b_table` SET times_chosen = times_chosen + 1 WHERE id = $row['id']";
/* run query against DB */
// exit foreach (stop processing records because the selection is made)
break 1;
}
}
// check here to make sure a record was selected, if not, then take record 1 and use it but
// don't forget to increment times_chosen
?>
This should explain itself, but in a nutshell, you are telling the routine to order the database records by the percentage chance highest chance first. Then, if percentage chance is greater than total, skip it and go to the next record.
UPDATE: So, given this set of records:
$records = array(
1 => array(
'id' => 1001, 'percentage_chance' => .67, 'name' => 'Function A', 'times_chosen' => 0,
),
2 => array(
'id' => 1002, 'percentage_chance' => .21, 'name' => 'Function A', 'times_chosen' => 0,
),
3 => array(
'id' => 1003, 'percentage_chance' => .12, 'name' => 'Function A', 'times_chosen' => 0,
)
);
Record 1 will be chosen 67% of the time, record 2 21% of the time, and record 3 12% of the time.
$sum = 0;
$choice = mt_rand(1,100);
foreach ($array as $item) {
$sum += chance($item); // The weight of choosing this item
if ($sum >= $choice) {
// This is the item we have selected
}
}
If I read you right, you want to select one of the items from the array, with some probability of each one being chosen. This method will do that. Make sure the probabilities sum to 100.