I have a search form with a possible 15 or so fields, however not all are required to carry out a search, for instance;
a user might search for a registered user in 'London' who works in 'Finance' but leave all other fields blank, such as $availability or $salary etc, so $_POST data may look something like:
$location = $_POST['location']; // Value - London
$sector = $_POST['sector']; // Value - Finance
$available = $_POST['available']; // Value - Any
$salary = $_POST['salary']; // Value - Any
Bearing in mind I may have another 12 or so 'Any' values from other fields, what is the best way to query the database (PHP/MySQL) to return results without looping through what would probably be dozens of queries.
To try and be a bit clearer, what i'd like is a query which would work something like (deliberate pseudo code):
SELECT * FROM table where location = 'location' AND if($availability !='Any') { available = '$available' } etc etc
Is something like this possible?
Or can I create a single string of all $_POST fields that !='Any' and then carry out a search on a row that contains all the words in the string (which I think would work in theory)?
I hope this makes sense to someone and you can point me in the right direction.
P.S. All $_POST is escaped and secured before interacting with database, just not included here :)
Try this:
$sql = "SELECT * FROM table where 1 ";
foreach ($_POST as $key => $post) {
if ($post != 'Any') {
$sql .= " AND $key = '$post' ";
}
}
// now you can run $sql against the database
Could you for argument sake collect all of the $_POST into a foreach($key=>$val) and then run the key through a switch or if statments that appends "AND x=x " to the statement?
Something like:
$sql = "SELECT * FROM table WHERE required='required'";
foreach($_POST as $key=>$val){
if(!empty($val)){ $sql .= " AND ".$key."='".$val"'"; }
}
Not sure if that works but in theory that is what i thought of first.
Thanks to those who offered answers, however I used the suggested answer found in the link above my question as it was clearer to me. Sample code pasted below FYI:
$tmp = "where ";
if($A and $A!="any" and $A!="not used")
$tmp .= "row1 = '".$A."'";
if($B and $B!="any" and $B!="not used")
$tmp .= "AND row2 = '".$B. "'";
if($C and $C!="any" and $C!="not used")
$tmp .= "AND row3 = '".$C."'";
$db_q = "Select * from table $tmp";
Thanks again, don't know where I'd be without SO.
Related
I have an online survey format with approx 200 input / select fields which I now want to write into my database. Now, since I dont want to go through the tedious process of writing out every single variable one-by-one in the query string, I was hoping that there would be an easier way, eg. using an array?
Here is a solution that I use. It requires that the database field names are the same as the <input> names:
$querystring1 = ""; $querystring2 = "";
foreach($_POST as $key => $var) {
$querystring2 .= "'".$var."',"; $querystring1 .= $key.",";
}
$insertquerystring = "(".$querystring1.") VALUES (".$querystring2.")";
mysql_query("INSERT INTO `mytablename` $insertquerystring") or die(mysql_error());
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 some search functionality that works with 3 drop down boxes. Based on the criteria chosen, a profile is returned. The 3 drop downs are:
County
Constituency
Gender
Now I am trying to build a query but have just realised that actually a person does not have to choose an option from each drop down and nor do I want them to.
So for instance I do not want to disable the search button until an option is selected from each drop down.
Having chosen a value from any drop down, and possibly having no value selected from any drop down at all, and just clicking the search button, I am trying to understand how I can cope with the unknown combinations.
My first thought was that I could use something like a truth table but I imagine this is simply overkill and in fact this is a very common piece of functionality.
Then I thought maybe I could have something like:
$county = "$_GET['county'];";
$constituency = "$_GET['constituency'];";
$gender = "$_GET['gender'];";
Then I could check to see if they are empty and somehow use this value, e.g.
if($county !== '') {
???SOMEHOW MAKE USE OF THIS IN AN SQL QUERY???
PERHAPS PASS IT TO ANOTHER PARAMETER
$sqlparams = "county = '$county'";
}
SELECT * FROM profile
WHERE {$sqlparams};
I think I'm on the right tracks but could use some guidance.
All help is greatly appreciated.
This should do want you want, I think.
<?php
$tooLookFor = array("county", "constituency", "gender");
foreach($tooLookFor as $key){
if(isset($_GET[$key]) && strlen($_GET[$key])>0){
$queryParams[] = $key.'="'.$_GET[$key].'"';
}
}
$query = "SELECT * FROM profile WHERE ".implode(' AND ', $queryParams);
?>
You could do something like:
$county = $_GET['county'];
$constituency = $_GET['constituency'];
$gender = $_GET['gender'];
$sqlparams = array();
if($county !== '') {
$sqlparams[] = "county = '$county'";
}
if($constituency !== '') {
$sqlparams[] = "constituency = '$constituency'";
}
if($gender !== '') {
$sqlparams[] = "gender = '$gender'";
}
$query = "SELECT * FROM profile";
if (count($sqlparams) > 0) {
$query .= " WHERE " . implode(" AND ", $sqlparams);
}
You can do that with something like this:
$where = array();
//repeat as needed
$where[$column] = $value;
$where2 = array();
foreach($where as $key => $value){
$where2[] = "$key = '$value'";
}
$where_string = implode(' AND ', $where2);
$where_string will have the string to insert after WHERE.
Yes, you are on the right track, you're just not at the right switch yet. ;)
You can't build the query until you know what you have to work with. So first, in your validation, determine (as you are doing) with the key words actually are and what fields they represent. Presumably these map to fields in tables, maybe 3 tables? Point is, your query will need to be dynamically built.
ok so I've been trying for a while now to get this to work but there has to be a better solution than what im thinking about. I'm fairly new to php/mysql so not sure how to do the following:
I have a search box that contains dropdowns for country, state, city
Now if the user only selects country and clicks on search it needs to filter the select by just country and show everything else.
if(!empty($_REQUEST['city']))
$city = $_REQUEST['city'];
else
$city= "%";
if(!empty($_REQUEST['state']))
$state= $_REQUEST['state'];
else
$state= "%";
if(!empty($_REQUEST['country']))
$country= $_REQUEST['country'];
select * from table where country = $country and state = $state and city = $city
problem with this is that those columns are ints so I can't use the "%" to filter it. I hope I was able to explain it any help is more than welcome. Thanks in advance
If you don't want to constrain a column, simply omit it from your query
never insert a string from $_REQUEST directly into a query string -- classic SQL injection flaw.
you probably want to enforce some sort of limit, lest the query return every single result in your database.
example:
<?php
$conditions = array();
if(!empty($_REQUEST['city']))
$conditions[] = "city = " . mysql_real_escape_string($_REQUEST['city']);
if(!empty($_REQUEST['state']))
$conditions[] = "state = " . mysql_real_escape_string($_REQUEST['state']);
if(!empty($_REQUEST['country']))
$conditions[] = "country = " . mysql_real_escape_string($_REQUEST['country']);
$sql = 'select * from table ';
if(!empty($conditions))
$sql .= ' where '. implode(' AND ', $conditions);
$sql .= ' LIMIT 1000';
$where = array();
if(!empty($_REQUEST['city'])) $where[] = "city = '".(int)$_REQUEST['city']."'";
if(!empty($_REQUEST['state'])) $where[] = "state = '".(int)$_REQUEST['state']."'";
if(!empty($_REQUEST['country'])) $where[] = "country = '".(int)$_REQUEST['country']."'";
$wherestring = if(count($where) != 0) ? " WHERE ".implode(' AND ', $where) : "" ;
$query = "SELECT * FROM table".$wherestring;
You may want to consider writing several query strings, one for just country, one for state and country and one for city, state and country. Alternatively you can assemble the query string based upon the different parameters you have to work with.
Example:
if(isset() || isset() || isset() ) //make sure at least one is set
{
$query_string = "SELECT * FROM table WHERE ";
if(isset($_REQUEST['country']))
{
$country = $_REQUEST['country'];
$query_string .= " country = $country";
}
if(isset($_REQUEST['state']))
{
$state = $_REQUEST['state'];
$query_string .= " state = $state";
}
if(isset($_REQUEST['city']))
{
$city = $_REQUEST['city'];
$query_string .= " city = $city";
}
}
else
{
//Else, if none are set, just select all the entries if no specifications were made
$query_string = "SELECT * FROM table";
}
//Then run your query...
So in english, the first thing you do is check your parameters, making sure you have something to work with before you try and concatenate empty variables together.
Then you make the base query string (as long as we have parameters) and leave it open ended so that we can add whatever parameters you need.
Next check each parameter, and if it is set, then concatenate that parameter onto the end of the query string.
Finally process the query by sending it to the SQL server.
Good luck!
h
Here're my suggestions.
I'm giving you an answer, even though you have three already. I'm thinking mine may be easier on the code-eyes.
Do not use the raw $_REQUEST value, as it's likely that the user can poison your database by feeding it fake $_REQUEST data. Though there may be better ways to do it, keep in mind the command "mysql_real_escape_string($string)".
A common method I've seen for solving this problem is written below. (The implode idea, basically. Frank Farmer does it as well in his.)
-
$__searchWheres = array(); //Where we'll store each requirement used later
foreach( array('city','state','country') as $_searchOption) {
if ( ! empty( $_REQUEST[$_searchOption] ) ) {
$__searchWheres[] = $_searchOption . '= "' . mysql_real_escape_string( $_REQUEST[$_searchOption] ) . '"';
}
}
$__query = 'select * from table' . (count($__searchWheres) > 0 ? ' WHERE ' . implode(' AND ',$__searchWheres) : ''); //Implode idea also used by Frank Farmer
//Select from the table, but only add the 'WHERE' key and where data if we have it.
mysql_query($__query);
Ok, i have a problem here...
I am sending values of drop down lists via ajax to this PHP file.
Now I want to search a mysql database using these values, which I have managed to do, BUT, only if I set the values to something...
Take a look:
$query = "SELECT * FROM cars_db WHERE price BETWEEN '$cars_price_from' AND '$cars_price_to' AND year BETWEEN '$cars_year_from' AND '$cars_year_to' AND mileage BETWEEN '$cars_mileage_from' AND '$cars_mileage_to' AND gearbox = '$cars_gearbox' AND fuel = '$cars_fuel'";
now, what if the user doesnt select any "price_from" or "year_from"... The fields are only optional, so if the user doesnt enter any "price from" or "year from", then the user wants ALL cars to show...
Do I have to write a query statement for each case or is there another way?
I do something similar to davethegr8 except I put my conditions in an array and then implode at the end just so I don't have to worry about which conditions got added and whether I need to add extra AND's.
For example:
$sql = "SELECT * FROM car_db";
// an array to hold the conditions
$conditions = array();
// for price
if ($car_price_from > 0 && $car_price_to > $car_price_from) {
$conditions[] = "(price BETWEEN '$cars_price_from' AND '$cars_price_to')";
}
elseif ($car_price_from > 0) {
$conditions[] = "(price >= '$cars_price_from')";
}
elseif ($car_price_to > 0) {
$conditions[] = "(price <= '$cars_price_from')";
}
else {
//nothing
}
// similar for the other variables, building up the $conditions array.
// now append to the existing $sql
if (count($conditions) > 0){
$sql .= 'WHERE ' . implode(' AND ', $conditions);
}
You could simply detect which parameters are missing in your PHP code and fill in a suitable default. eg
if (!isset($cars_mileage_to))
$cars_mileage_to = 500000;
You can build you query, adding the "where" part only if your variables are different from "".
or if you're using mysql 5.x, you can also use subselects:
http://dev.mysql.com/doc/refman/5.0/en/subqueries.html
don't forget to validate the input. It's trivial with firebug, for example, to inject some tasty sql.