I have checkboxes that represent the condition of a product. When a user checks for example Excellent, the value 1 is stored in a GET-variable like this:
...index.php?condition=1
Now, when the user checks multiple boxes (which has to be possible), it looks like this:
...index.php?condition=1,2,3
Obviously, I have to query my database in order to show the products corresponding to the user's choice(s).
if the user only checks one box, the statement is simple:
if (!empty($_GET['condition'])){
$sql = $sql . " AND (Condition = '".$_GET['condition']."')";
}
But what if the user checks multiple boxes? How would the statement have to look? (is it even possible to solve it this way?
thanks!
This is the script that creates the address:
<script>
$('#condition_select input:checkbox').change(function() {
var condition = $("#condition_select input:checkbox:checked").map(function() {
return this.value;
}).get().join(',');
$("#submit_checkboxes").find("a").attr('href', 'index.php?condition=' + condition);
}).change();
</script>
HTML:
<div class="mutliselect" id="condition_select">
<form method="POST" action="">
<ul>
<li><input type="checkbox" id="d1" value="1"'; if(strpos($_GET['condition'],'1') !== false){ echo 'checked="checked"';} echo'/><label for="d1" class="checkbox_title">Neu</label></li>
<!-- and 6 more of these -->
Is there a way to solve this without having to create a separate GET-variable for each checkbox?
UPDATE (once more updated accrding to comments and questions updates):
Question updated, so I will update my answer to. Use explode (http://php.net/manual/en/function.explode.php), to get all values, and implode to formulate query:
$values = explode(',', $_GET['condition']);
// VALIDATE each of values to match Your type.
if (!empty($values)) {
// $values = [1, 2, 3]
foreach ($values as $key => $value) {
$values[$key] = '(condition = \''.$value.'\')';
}
// $values = ['(condition = \'1\')', '(condition = \'2\')', '(condition = \'3\')']
$query = implode(' OR ', $values);
// $query = '(condition = \'1\') OR (condition = \'2\') OR (condition = \'3\')',
$sql = $sql . ' AND ( '.$query.' )';
}
This is Your solution I think (MYSQL multiples AND: http://forums.mysql.com/read.php?10,250552). Example of explode working:
$string = '1,2,3,4,asd,fgh';
$array = explode(',', $string);
print_r($array[0]); // 1
print_r($array[3]); // 4
print_r($array[5]); // 'fgh'
This is a fragment of answer before edits, but I think it is worth to left it here:
Hoverwer, there are many security holes in it!!!
YOU MUST verify the user data. If someone pass in the address for example:
index.php?condition=; SHOW TABLES FROM database;
It can potentialy show some data. As You can see, user can also go to address with delete statemant, or INSERT INTO users... etc.
So in that case YOU SHOULD switch to PDO (for example) http://php.net/manual/en/pdo.prepare.php, and make prepared statements. Verify user data so if You need the number, he can pass only number.
You can use isset also: isset vs empty vs is_null. It is not a must, but sometimes can be useful. With each form you can also check for isset ($_POST['submit']) as many robots that spam POST forms, sometimes just ommit the submit button. It will decrease the amount of requests I think.
Remember that using POST and GET forms ALWAYS allow user to send his own POST / GET requests. In that case, server side verification is a MUST.
PS. Sorry for capital letters, they are used only to make it really STRONG. Verify user data ;).
Best regards.
Related
This is the input fields
<?php while($educationalQualificationsFromDB = Database::fetchData($queryForEducationalQualifications))
{
$eduQualifcationId = $educationalQualificationsFromDB['education_qualification_id'];
$eduQualifcation = $educationalQualificationsFromDB['edu_qualification'];
echo "<input class='form-control' type='text' name='eduqualification[]' value='$eduQualifcation'>";
echo "<br>";
}
?>
This is the query I used,
$eduQualifications = $_POST['eduqualification'];
foreach($eduQualifications as $oneEduQualifications)
{
Database::query("UPDATE educational_qualification SET edu_qualification = '$oneEduQualifications'");
}
I'll simply explain like this there are multiple values coming from the database from the educational qualifications table.I have used a while loop to fetch them all inside inputs.And there are several inputs right.So I need a condition to update all those relevant database data.I used foreach loop to fetch data from the inputs cause i used the name of the input fields as an array.When I update them using foreach loop it update all records with the same name.Please explain me why such thing happened and give me a solution to update all relevant multiple database values with the relevant input values.
An UPDATE query will update all rows, unless constrained to specific rows by a WHERE clause. So you'll need to add something like:
UPDATE educational_qualification
SET edu_qualification = '$oneEduQualifications'
WHERE education_qualification_id = '$eduQualifcationId'
So you need to transport the $eduQualifcationId through the form together with the $eduQualifcation as well. The best way for that is to just use it as the $_POST array key:
<input type='text' name='eduqualification[$eduQualifcationId]' value='$eduQualifcation'>
Now your $_POST array will look something like:
array(
'eduqualification' => array(
'42' => '69'
)
)
So you can do:
foreach ($_POST['eduqualification'] as $id => $qualification) {
Database::query("UPDATE educational_qualification SET edu_qualification = '$qualification' WHERE education_qualification_id = '$id'");
}
As is, you appear to be open to both SQL and HTML injection BTW, which you'll want to fix:
How can I prevent SQL injection in PHP?
How to prevent XSS with HTML/PHP?
If you have multiple users, and certain users should only be allowed to update their own data, then you'll want even more constrains and checks, something like:
UPDATE educational_qualification
SET edu_qualification = '$oneEduQualifications'
WHERE education_qualification_id = '$eduQualifcationId'
AND user = '$current_user'
Because POST requests are just HTTP requests, and anyone can send any arbitrary data in an HTTP request…
So I want to build a filter functionality where the user can fill out as many inputs on the form page as they like. So they may leave some filters blank. How do I search my database for only the values the user has submitted? The only way I know how to do this would be a massive cluster of if statements to account for every possible combination of forms they filled out, e.g.:
<?php
if(isset($max) && isset($min) && isset($rank)) {
mysqli_query($connect, "SELECT * FROM books WHERE ...")
} else if (isset($max) && (isset($min))) {
// so on and so forth
}
Now the code above may look manageable, and it would be if I only had 3 filters, but in this case I have a fairly large list of filters that I only need to apply if the user submitted something. All-in-all I think there is something like 30 potential combinations of the different filters.
Thanks in advance for your help.
You can construct the query string part by part. First you set:
$s = "SELECT * FROM books WHERE 1 ";
Then on each and every filter you write:
if(isset(...)) {
$s .= " AND myfield = $myvalue ";
}
And in the end you can append:
$s .= " ORDER BY somewhat;";
Of course some escaping should be done or better use mysqli_ queries.
Placing the condition '1' right after WHERE helps you use the AND operator in each line regadles of is it the first active condition or not. You can put the condiotions in a while loop if your POST data is well structured. You can name your HTML input fileds as 'filter[1]', 'filter[2]' and so on and then you can iterate on them with a loop.
Action points
define an array (v) of all the possible values keys
array_flip (v) and array_intersect_key $_POST with the new (v)
array_filter the new (v) to remove unfilled/blank values (or filter by your custom callback if you also want to include null/false values)
implode the new (v) by key and value using array_map to build the query
So
$possibleValuesKeys = ['min', 'max', 'rank', ...];
$values = array_filter(array_intersect_key($_POST, array_flip($possibleValuesKeys)));
$sql = 'SELECT * FROM table WHERE ' . implode(' AND ', array_map(
function ($v, $k) { return sprintf("%s = '%s' ", $k, $v); },
$values,
array_keys($values)
))
I have a database containing a number of tables. I also have a web-based application that is connected to it. For now I am using prepared queries.
I am trying to create a general query that will be able to take a variable number of input columns from different tables. (Basically the user checks boxes that create php variables that I need to pass to the query).
If I know that there will be let say 2 columns needed, it's easy, I only need to do something like,
SELECT $col1, $col2 FROM $table1 INNER JOIN $table2;
How can I change that so that any number of variables can be input in the query?
Thanks in advance,
Zohm
EDIT: I think I could maybe do an if/else condition in PHP or a switch and each case would correspond to a number of input columns, and each case would have its query. But this would do a lot of cases (the user could click 10 boxes for example) and It does not really seems right to do that. Moreover in the future if I need more cases I will have to change the code, which I rather not have to do.
i assume your form elements names are the table fields you are looking for. if this is the case you can loop through the post to build your fields table. Im not sure how you are setting a variable to have 2 values...
$_POST['field1'] = "true";
$_POST['field2'] = "true";
$_POST['field3'] = "false";
$_POST['field4'] = "true";
$fields = "";
foreach ($_POST as $key => $value)
{
$fields .= $key . ",";
}
which will end up with
$fields = "field1,field2,field4,";
now you have to remove that last comma,
$fields = substr($fields,0,-1);
so then you can:
$query = "SELECT " . $fields . " from table1...and so on.
I have a form where I am trying to implement a tag system.
It is just an:
<input type="text"/>
with values separated by commas.
e.g. "John,Mary,Ben,Steven,George"
(The list can be as long as the user wants it to be.)
I want to take that list and insert it into my database as an array (where users can add more tags later if they want). I suppose it doesn't have to be an array, that is just what seems will work best.
So, my question is how to take that list, turn it into an array, echo the array (values separated by commas), add more values later, and make the array searchable for other users. I know this question seems elementary, but no matter how much reading I do, I just can't seem to wrap my brain around how it all works. Once I think I have it figured out, something goes wrong. A simple example would be really appreciated. Thanks!
Here's what I got so far:
$DBCONNECT
$artisttags = $info['artisttags'];
$full_name = $info['full_name'];
$tel = $info['tel'];
$mainint = $info['maininst'];
if(isset($_POST['submit'])) {
$tags = $_POST['tags'];
if($artisttags == NULL) {
$artisttagsarray = array($full_name, $tel, $maininst);
array_push($artisttagsarray,$tags);
mysql_query("UPDATE users SET artisttags='$artisttagsarray' WHERE id='$id'");
print_r($artisttagsarray); //to see if I did it right
die();
} else {
array_push($artisttags,$tags);
mysql_query("UPDATE users SET artisttags='$artisttags' WHERE id='$id'");
echo $tags;
echo " <br/>";
echo $artisttags;
die();
}
}
Create a new table, let's call it "tags":
tags
- userid
- artisttag
Each user may have multiple rows in this table (with one different tag on each row). When querying you use a JOIN operation to combine the two tables. For example:
SELECT username, artisttag
FROM users, tags
WHERE users.userid = tags.userid
AND users.userid = 4711
This will give you all information about the user with id 4711.
Relational database systems are built for this type of work so it will not waste space and performance. In fact, this is the optimal way of doing it if you want to be able to search the tags.
$url = mysql_real_escape_string($_POST['url']);
$shoutcast_url = mysql_real_escape_string($_POST['shoutcast_url']);
$site_name = mysql_real_escape_string($_POST['site_name']);
$site_subtitle = mysql_real_escape_string($_POST['site_subtitle']);
$email_suffix = mysql_real_escape_string($_POST['email_suffix']);
$logo_name = mysql_real_escape_string($_POST['logo_name']);
$twitter_username = mysql_real_escape_string($_POST['twitter_username']);
with all those options in a form, they are pre-filled in (by the database), however users can choose to change them, which updates the original database. Would it be better for me to update all the columns despite the chance that some of the rows have not been updated, or just do an if ($original_db_entry = $possible_new_entry) on each (which would be a query in itself)?
Thanks
I'd say it doesn't really matter either way - the size of the query you send to the server is hardly relevant here, and there is no "last updated" information for columns that would be updated unjustly, so...
By the way, what I like to do when working with such loads of data is create a temporary array.
$fields = array("url", "shoutcast_url", "site_name", "site_subtitle" , ....);
foreach ($fields as $field)
$$field = mysql_real_escape_string($_POST[$field]);
the only thing to be aware of here is that you have to be careful not to put variable names into $fields that would overwrite existing variables.
Update: Col. Shrapnel makes the correct and valid point that using variable variables is not a good practice. While I think it is perfectly acceptable to use variable variables within the scope of a function, it is indeed better not use them at all. The better way to sanitize all incoming fields and have them in a usable form would be:
$sanitized_data = array();
$fields = array("url", "shoutcast_url", "site_name", "site_subtitle" , ....);
foreach ($fields as $field)
$sanizited_data[$field] = mysql_real_escape_string($_POST[$field]);
this will leave you with an array you can work with:
$sanitized_data["url"] = ....
$sanitized_data["shoutcast_url"] = ....
Just run a single query that updates all columns:
UPDATE table SET col1='a', col2='b', col3='c' WHERE id = '5'
I would recommend that you execute the UPDATE with all column values. It'd be less costly than trying to confirm that the value is different than what's currently in the database. And that confirmation would be irrelevant anyway, because the values in the database could change instantly after you check them if someone else updates them.
If you issue an UPDATE against MySQL and the values are identical to values already in the database, the UPDATE will be a no-op. That is, MySQL reports zero rows affected.
MySQL knows not to do unnecessary work during an UPDATE.
If only one column changes, MySQL does need to do work. It only changes the columns that are different, but it still creates a new row version (assuming you're using InnoDB).
And of course there's some small amount of work necessary to actually send the UPDATE statement to the MySQL server so it can compare against the existing row. But typically this takes only hundredths of a millisecond on a modern server.
Yes, it's ok to update every field.
A simple function to produce SET statement:
function dbSet($fields) {
$set='';
foreach ($fields as $field) {
if (isset($_POST[$field])) {
$set.="`$field`='".mysql_real_escape_string($_POST[$field])."', ";
}
}
return substr($set, 0, -2);
}
and usage:
$fields = explode(" ","name surname lastname address zip fax phone");
$query = "UPDATE $table SET ".dbSet($fields)." WHERE id=$id";