How write dynamic query staring using PHP - php

Dear experts,
Let say I have to search 3 co-related options 1)name 2)address 3)Phone. So, I have to write 8[eight] separate queries.pls see the example below….
$name= $_POST['name'];
$address = $_POST['address'];
$phone= $_POST['phone'];
if($name!=""&& $address==""&& $phone=="")
{ $searching_query="SELECT id,name,address from info where info LIKE '%$info%'";}
.....................................
......................................
..........................................
else if($name!=""&&$address==""&&$phone!="")
{ $searching_query="SELECT id,name,address from info where name LIKE '%$ name%' AND phone LIKE '$phone' "; }
else if ($name!=""&&$address!=""&&$phone!="")
{ $searching_query="SELECT id,name,address from info where name LIKE '%$ name%' AND address LIKE '%$address%' AND phone LIKE '$phone' ";}
So, if the correlated searching option is more than that then I have to write more and more queries.
Now my question is: how can I write the exact query dynamically. I mean WHERE clause of query will be generated based on posted values.
Please help!
Thx,riad

Use arrays! and escape user input with vendor specific functions to protect against SQL injections. mysql_real_esacpe_string() should be used in this case.
$where = array();
foreach(array('name','address','phone') as $key) {
if(isset($_POST[$key]) && !empty($_POST[$key])) {
$where[] = $key . " LIKE '%" . mysql_real_escape_string($_POST[$key]) . "%'";
}
}
$query = "SELECT id,name,address FROM info";
if(empty($where)) {
$query .= "WHERE info LIKE '%" . mysql_real_escape_string($info) . "%'";
} else {
$query .= "WHERE " . implode(' AND ',$where);
}

You can always 'join' array entries to a string with a separator. If in this case you would use "AND" as your separator, you may be helped:
$like_clauses = array();
$fields = array( "phone", "address", "name" ) ;
foreach( $fields as $field) {
if( !array_key_exist( $field, $_POST ) ) continue;
$like_clauses[$field]=
$field." LIKE '%"
// thanx to #darko petreski's comment:
.mysql_real_escape_string($_POST[$field])
."%'";
}
$query = "SELECT id,name,address from info where "
.implode( "AND", $like_clauses );
(note: untested - grab the idea)
EDIT -- added mysql_real_escape_string to avoid injection vulnerability

Related

Handling optional search parameters in a PHP SQL query

I'm querying my SQL database in a PHP file from up to three optional search fields (passed through by jQuery). Any one, two or three of these fields can be used at any time to make the query as expansive or as narrow as the user likes. If nothing is in a search field nothing will be returned.
I've written the code so far to handle very basic one search queries and have just begun to add in the multiple parameters - this is where it's starting to get tricky. I can query two fields together without too much bother but adding a third LOCATION parameter is beginning to take up too much code for all of the querying possibilities a user might make.
Here's how my PHP file is set up for two parameters:
if (!empty($_POST['title']) && (!empty($_POST['name'])))
{
require '../db/connect.php';
$sql = "SELECT
....
FROM
....
WHERE
`table 3`.`TRACKTITLE` = '" . mysql_real_escape_string(trim($_POST['title'])) . "' AND `table 3`.`ARTIST` = '" . mysql_real_escape_string(trim($_POST['name'])) . "'";
}
if (!empty($_POST['name']))
{
require '../db/connect.php';
$sql = "SELECT
...
FROM
...
WHERE
`table 3`.`ARTIST` = '" . mysql_real_escape_string(trim($_POST['name'])) . "'";
}
if (!empty($_POST['title'])) {
require '../db/connect.php';
$sql = "SELECT
...
FROM
...
WHERE
`table 3`.`TRACKTITLE` = '" . mysql_real_escape_string(trim($_POST['title'])) . "'";
}
$result = mysql_query($sql);
$data = array();
while ($array = mysql_fetch_assoc($result)) {
$data[] = $array;
Which is the simplest way to build a query with multiple optional parameters in PHP, accounting for any additional parameters that might be added on at a later date? I've read up on isnull values but do they perform a similar function to !emtpy?
Do something along this line:
$whereclauses = array();
$subsets = false;
// for every field
if(!empty($_POST['name']))
{
$subsets = true;
$whereclauses[] = " artist = ". mysql_real_escape_string(trim($_POST['name']));
}
if($subsets)
{
$whereclauses = implode(", ". $whereclauses);
}
else
{
$whereclauses ="";
}
// now build your query

$wpdb->get_results($query); Returns NULL with variable $query - Same query works hardcoded

I've been trying to debug this script for a month. The rest of the program is already built and this one thing just will not work. The issue is the $query variable, it returns null unless I hard code - which isn't possible with a search form. I've tried adding '\n', I've tried just putting in the returns, I've changed the " to ' for the beginning. I've tested the rest of the code outside of this block and it all works. I've run tests on this block as you can see from commented out echo statements below. Those all test fine. The $query string built by the function returns the correct data when hard coded or in the database browser. I'm stuck! Help please.
[code snippet]
if(isset($_POST['submit'])) {
// define the list of fields
$fields = array('lastname', 'firstname', 'dob', 'city', 'telephone', 'email', 'user_id');
$conditions = array();
// loop through the defined fields
foreach($fields as $field){
//echo "Field is ".$field."\n";
// if the field is set and not empty
if(isset($_POST[$field]) && $_POST[$field] != '') {
//echo "Field is: ".$field."\n".$field." is: ".$_POST[$field]."\n";
// create a new condition while escaping the value inputed by the user (SQL Injection)
$conditions[] = "$field LIKE '%" . mysql_real_escape_string($_POST[$field]) . "%'
";
}
}
// builds the query
$query = "\"
SELECT *
FROM wp_ct_ad_client_db_table
";
// if there are conditions defined
$query_user_id = "user_id = ".$user_id."
\"";
array_push($conditions, $query_user_id);
if(count($conditions) > 0) {
// append the conditions
$query .= "WHERE " . implode(' AND ', $conditions); // you can change to 'OR', but I suggest to apply the filters cumulative
}
echo "Query String: ".$query."\n";
//$result = $wpdb->get_results($query);
$my_query = $query;
echo "Test My Query Logic \n";
//$result = $wpdb->get_results("SELECT * FROM wp_ct_ad_client_db_table WHERE lastname LIKE '%A%' AND user_id = $user_id;");
//$result = $wpdb->get_results($my_query);
$result = $wpdb->get_results($my_query, A_ARRAY);
var_dump($result);
[/code snippet]

MySql Search Query for Two Combined Fields

I am working on a site that allows users to list boats and yachts for sale. There is a mysql database that has a table "yachts" and among other fields ther are "make" and "model".
When people come to the site to look for boats for sale there is a search form, one of the options is to enter the make and/or model into a text field. The relevant where clause on the results page is the following
WHERE ( make LIKE '%$yacht_make%' OR model LIKE '%$yacht_make%')
This is working if someone enters either the make or model but not if they enter both.
For example, if someone enters "Jeanneau", the make, it finds the boat with that make, or if they enter "Sun Odyssey", the model, it finds the boat of that model, but if they enter "Jeanneau Sun Odyssey" it comes up empty.
Is there is a way to write a query where all three ways of entering the above search criteria would find the boat?
Here is the site http://yachtsoffered.com/
Thanks,
Rob Fenwick
Edit:
The query is built with a php script here is the script
if(!empty($yacht_id)) {
$where = " WHERE yacht_id = $yacht_id ";
} else {
$where = " WHERE ( make LIKE '%$yacht_make%' OR model LIKE '%$yacht_make%') ";
if(!empty($year_from) && !empty($year_to)){
$where .= "AND ( year BETWEEN $year_from AND $year_to ) ";
}
if(!empty($length_from) && !empty($length_to)){
$where .= "AND ( length_ft BETWEEN $length_from AND $length_to ) ";
}
if(!empty($price_from) && !empty($price_to)){
$where .= "AND ( price BETWEEN $price_from AND $price_to ) ";
}
if ($sail_power != 2){
$where .= "AND ( sail_power = $sail_power ) ";
}
if (count($material_arr) > 0){
$material = 'AND (';
foreach ($material_arr as $value) {
$material .= ' material LIKE \'%' . $value . '%\' OR';
}
$material = substr_replace ( $material , ') ' , -2 );
$where .= $material;
}
if (count($engine_arr) > 0){
$engine = 'AND (';
foreach ($engine_arr as $value) {
$engine .= ' engine LIKE \'%' . $value . '%\' OR';
}
$engine = substr_replace ( $engine , ') ' , -2 );
$where .= $engine;
}
if (count($type_arr) > 0){
$type = 'AND (';
foreach ($type_arr as $value) {
$type .= ' type LIKE \'' . $value . '\' OR';
}
$type = substr_replace ( $type , ') ' , -2 );
$where .= $type;
}
if (count($region_arr) > 0){
$region = 'AND (';
foreach ($region_arr as $value) {
$region .= ' region LIKE \'' . $value . '\' OR';
}
$region = substr_replace ( $region , ') ' , -2 );
$where .= $region;
}
$where .= 'AND ( active = 1 ) ORDER BY yacht_id DESC';
}
$sql = "SELECT * FROM $tbl_name $where LIMIT $start, $limit";
$result = mysql_query($sql);
There are many ways to do it, the easiest one in my opinion is:
$search = preg_replace('/\s+/','|', $yacht_make);
$sql = "select * from yacht where concat_ws(' ',make,model) rlike '$search'";
This replaces all whitespace with |, that is used as OR in regexp-powered-like query on concatenation of all searchable fields. The speed of it may be questionable in heavy trafic sites but is quite compact and easy to add more fields.
Your problem is that in your query you are searching for the exact substring "Jeanneau Sun Odyssey", which is neither a make nor a model.
The easiest solution is to use to separate input boxes for make and model. But if you really need to use a single input box, your best bet would be to split on spaces and add clauses for each separate word, so your query will end up looking something like
WHERE make like '%sun%' OR model like '%sun%'
OR make like '%odyssey%' OR model like '%odyssey%'
OR make like '%Jeanneau%' OR model like '%Jeanneau%'
Thanks everyone I ended up using dev-null-dweller's solution above
I revised my code as following,
to get the value and escape here is the code,
if (isset($_GET['yacht_make'])) {
$yacht_make = cleanString($_GET['yacht_make']);
$yacht_make = preg_replace('/\s+/','|', $yacht_make);
} else {
$yacht_make = NULL;
}
And I revised the first few lines of the php query building code I posted above to read,
if(!empty($yacht_id)) {
$where = " WHERE yacht_id = $yacht_id ";
} else {
$where = " WHERE ( yacht_id LIKE '%' )";
if(!empty($yacht_make)){
$where .= "AND ( CONCAT_WS(' ',make,model) RLIKE '$yacht_make') ";
}
It is working nicely, although it brings up more results than I would like for "Jeanneau Sun Odyssey" as it brings up "Bayliner Sunbridge", I assume because it is matching "Sun".
But it is a big improvement from what I had.
Thanks All
Rob Fenwick
You could also use:
WHERE make LIKE '%$yacht_make%'
OR model LIKE '%$yacht_make%'
OR '$yacht_make' LIKE CONCAT('%', make, '%', model, '%')
OR '$yacht_make' LIKE CONCAT('%', model, '%', make, '%')
It will not be very efficient and still not catch all possibilities, e.g. if the user provide the make and a part of the model name, like 'Jeanneau Odyssey' or in wrong order: Sun Jeanneau Odyssey.
After checking out your site it appears you are only taking input from one text field and searching for that string in each field.
So, you can either use full text searches (linkie) or you could split your string by spaces and generate a WHERE cause on the fly. Here is a rough example:
$searchterms = explode (' ', $input);
$sql .= "... WHERE"; /* obviously need the rest of your query */
foreach ($searchterms as $term) {
if ((substr ($string, -5) != 'WHERE') &&
(substr ($string, -3) == ' ||') { $sql .= " ||"; }
$sql .= " make LIKE '%$term%' || model LIKE '%$term%'";
}

PHP SQL: Way to skip over section of a query if variable is blank

I'm writing a query that uses input from a search form where Brand, Type and Price are optional input fields:
SELECT * FROM `database` WHERE `brand` LIKE "%' . $brand . '%" AND `type` LIKE "%' . $type. '%" AND `price` LIKE "%' . $price . '%"
I am wondering if there is a way to say 'all' if nothing is entered into one of the fields. For example if they do not enter a value in the price field is there a way to tell SQL to just say ignore that section, eg:
AND `price` LIKE "*";
So the reuslts are still filtered by Brand and Type but can have any Price.
Any advice on this is appreciated! Thanks
As Ariel mentioned, it would be better to have PHP do the filtering as you build the query. Here's a code sample for doing it that way:
<?php
$sql = 'SELECT * FROM `database`';
$where = array();
if ($brand !== '') $where[] = '`brand` LIKE "%'.$brand.'%"';
if ($type !== '') $where[] = '`type` LIKE "%'.$type.'%"';
if ($price !== '') $where[] = '`price` LIKE "%'.$price.'%"';
if (count($where) > 0) {
$sql .= ' WHERE '.implode(' AND ', $where);
} else {
// Error out; must specify at least one!
}
// Run $sql
NOTE: Please, please, please make sure that the $brand, $type, and $price variable contents are sanitized before you use them this way or you make yourself vulnerable to SQL injection attacks (ideally you should be using the PHP PDO database connector with prepared statements to sanitize the input).
Normally you do that in the front end language, not SQL.
But price LIKE '%' does, in fact, mean all (except for NULLs). So you are probably fine.
If you have your form fields organized, you can do something like:
<?php
$fields = array(
// Form // SQL
'brand' => 'brand',
'type' => 'type',
'price' => 'price',
);
$sql = 'SELECT * FROM `database`';
$comb = ' WHERE ';
foreach($fields as $form => $sqlfield)
{
if (!isset($_POST[$form]))
continue;
if (empty($_POST[$form]))
continue;
// You can complicate your $fields structure and e.g. use an array
// with both sql field name and "acceptable regexp" to check input
// ...
// This uses the obsolete form for mysql_*
$sql .= $comb . $sqlfield . ' LIKE "%'
. mysql_real_escape_string($_POST[$form])
. '"';
/* To use PDO, you would do something like
$sql .= $comb . $sqlfield . 'LIKE ?';
$par[] = $_POST[$form];
*/
$comb = ' AND ';
}
// Other SQL to go here
$sql .= " ORDER BY brand;";
/* In PDO, after preparing query, you would bind parameters
- $par[0] is value for parameter 1 and so on.
foreach($par as $n => $value)
bindParam($n+1, '%'.$value.'%');
*/

select table filter by querystring php

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);

Categories