Drafting SQL search query based on user entry - php

I'm currently coding a simple search script in PHP that requires three variables from the user namely:
$Capacity, $Location and $RoomType
Capacity is a required field which the jquery validate plugin checks for numerical entry on input - but Location and RoomType are optional.
I'm trying to now draft a SQL query that will search the table rooms.
There are three columns in the table also called Capacity, Location and RoomType that I want to search using the variables.
How would I write this SQL query? Especially with $Capacity being required, $Location / $RoomType expected to be left blank or filled in at the users discretion?

You could use LIKE ...% in your sql query, so that even when blank, it'll be treated as a wildcard.
$q = 'SELECT * FROM foo WHERE capacity = "'.$capacity.'" AND location LIKE "'.$location.'%" AND roomtype LIKE "'.$roomtype.'%"';
Of course, remember to escape the inputs.

Something like this should work:
function BuildSearchQuery($Capacity, $Location, $RoomType)
{
$where = array();
if (!empty($Capacity))
{
$where[] = "Capacity = '" . mysql_real_escape_string($Capacity) . "'";
}
if (!empty($Location))
{
$where[] = "Location = '" . mysql_real_escape_string($Location) . "'";
}
if (!empty($RoomType))
{
$where[] = "RoomType = '" . mysql_real_escape_string($RoomType) . "'";
}
if (empty($where))
{
return false;
}
$sql = "select * from `table` where ";
$sql += implode(" AND ", $where);
return $sql;
}
Although nowadays many frameworks exists that allow you to do this more easily and less error-prone than manually crafting queries.

$query =select * from table where Capacity =$Capacity
if(isset($Location) && $Location!='') $query.= and Location LIKE '%$location%'
if(isset($RoomType) && $RoomType!='') $query.= and RoomType LIKE '%$RoomType%'
Making use of LIKE or = operator in query is upto you.

Depend on how complex it is (and or not ???)
But basically
Select ... From Rooms Where Capacity = #Capacity
and ((Location = #Location) Or (IsNull(#Location,'') = ''))
and ((RoomType = #RoomType) or (IsNull(#RoomType,'') = ''))
Or some such.
If you aren't using parameterised queryies then replace #.... with the escaped inputs.

Related

Constructing a table from a MySQL database, and then being able to filter the table without reloading the page

I'm working on a website that presents leaderboard data from a MySQL database as a table, that which can be filtered and searched through by the user. I was able to construct the table through PHP calls, such as
php echo $row['ranking'];
Similarly, I was able to create a pagination that limits the MySQL query to 50 rows per page.
What I haven't been able to achieve, is the filtering/searching of the data, as well as a pagination that doesn't require the reloading of the page. I attempted to create filtering through PHP variables
$sql = "SELECT * FROM New_2v2_Data $filters";
but couldn't get it to work outside of just editing the PHP code.
$racevar = '%';
$classvar = '%';
$specvar = '%';
$playervar = '%';
$realmvar = '%';
$factionvar = '%';
$r1 = '0';
$r2 = '1800';
$race ="raceId LIKE '$racevar'";
$class = "classId LIKE '$classvar'";
$spec ="specId LIKE '$specvar'";
$player ="player LIKE '$playervar'";
$realm ="realmName LIKE '$realmvar'";
$faction="factionId LIKE '$factionvar'";
$rating ="rating between $r1 and $r2";
$filters = "WHERE $race AND $class AND $spec AND $player AND $realm AND $faction AND $rating";
$sql = "SELECT * FROM New_2v2_Data $filters";
$rs_result = mysql_query ($sql); //run the query
I've found filtering solutions for individual variables, for example names, but I haven't been able to find anything that takes in multiple variables into account. Even then, the filtering only worked on tables that were static.
I was thinking maybe if a dropdown/checkbox were to change a PHP variable depending on what is chosen, and then reloading the PHP for the table to include the additional "WHERE" statement, filtering could work.
Some advice on how I would go about doing this would be great, thank you.
You can conditionally include the various limits and build the SQL just from those which have something set.
$racevar = 'a'; // A value to show when this would be included
$classvar = '%';
$specvar = '%';
$playervar = '%';
$realmvar = '%';
$factionvar = '%';
$r1 = '0';
$r2 = '1800';
$condition= [];
$bindData = [];
if ( $racevar != '%'){
$condition[] ="raceId LIKE ?";
$bindData[] = $racevar;
}
if ( $classvar != '%'){
$condition[] = "classId LIKE ?";
$bindData[] = $classvar;
}
// Repeat above for all of the conditions
if ( $r1 != 0 or $r2 != 0 ) {
$condition[] = "rating between ? and ?";
$bindData[] = $r1;
$bindData[] = $r2;
}
$sql = "SELECT * FROM New_2v2_Data";
if ( count($condition) > 0 ) {
$sql .= " WHERE ".implode(' and ', $condition);
}
echo $sql;
The idea is to build a list of conditions, only when the values have something which is a limit. This can then be added as a where clause.
You then can have various input fields/select fields which allow the user to select the criteria and call this routine with the selections.
I've updated the answer to use bind variables, so that using prepare will give you more security and then you can either bind the values or (using PDO) execute with the array of bind values.
You need to make the filters selectable or dynamic in a way that you can pass them on to your SQL statement.
Your solution for the dropdown could be one of them indeed. You could even do that with a 'search' input text field. Then you make your WHERE statement:
WHERE (`column1` LIKE '%$search%' OR `column2` LIKE '%$search%' OR `column3` LIKE '%$search%',) LIMIT 0,10

PHP to create MySQL query from URL query

I have a relatively small search form that I want people to use to search my SQL database.
The only way I've done this before was with a billion nested if statements. Is there a better way to do this?
I am parsing my URL query string, so I have my variables of say:
$city
$bedrooms
$elementaryschool
If I were to just try to try:
$sql = "SELECT * FROM $table_name WHERE ";
if(isset($city)) {
$sql .= " `City` LIKE " . $city;
}
if(isset($bedrooms)) {
$sql .= " AND `Bedrooms` >= " . $bedrooms;
}
if(isset($elementaryschool)) {
$sql .= " AND `ElementarySchool` = " . $elementaryschool;
}
Then I run into an issue when $city isn't set because my query ends up with "SELECT * FROM $table_name WHERE AND Bedrooms >= $bedrooms"
That wouldn't exactly work. What are my options?
I completely understand how to do it if I am including all parameters in my query, which seems to be what all previous questions have asked. But how do I do this when not all fields will have a value? I have a total of 12 possible fields to use for searching, and they can search by just 1 or by all 12.
As I mentioned before, all of the questions I have been able to find refer to coming up with one static SQL query, instead of one that will have varying number of parameters.
I would go with:
$sql = "SELECT * FROM $table_name";
$where = array();
$params = array();
and then:
if(isset($city)) {
$where[] = "City LIKE ?";
$params[] = $city;
}
if(isset($bedrooms)) {
$where[] = "Bedrooms >= ?";
$params[] = $bedrooms;
}
if(isset($elementaryschool)) {
$where[] = "ElementarySchool = ?";
$params[] = $elementaryschool;
}
and finally:
if(!empty($where)) {
$sql .= "WHERE " . implode(" AND ", $where);
}
$result = $db->prepare($sql)->execute($params);
PLEASE NOTE that here, since I do not know what kind of database layer/abstraction you are using, $db represents the database connection, prepare() is used to create a prepared statement, and execute() tu run it, as you would do using PDO; this also protects against SQL injection.

How to select all where the condition is null?

I have a php code with a query:
$query = "SELECT * FROM TDdb WHERE status = $status AND occupation =$occupation";
I am sending the values status and occupation with a client application to this php code.
This works when I send both status and occupation. But I want it to return rows if I just send status but not occupation also ( I mean no matter what the occupation is).
does anyone have any suggestions?
I would appreciate any help.
PS: I want to do it without if statement and just but changing the query
Personally I would create a base query and append conditions wherever you have them, like so:
$sql = 'SELECT * FROM TDdb';
$conditions = array();
$args = array();
if ($action) {
$conditions[] = 'status = :status';
$args[':status'] = $status;
}
if ($occupation) {
$conditions[] = 'occupation = :occupation';
$args[':occupation'] = $occupation;
}
if ($conditions) {
$sql .= ' WHERE ' . join(' AND ', $conditions);
}
$stmt = $db->prepare($sql);
$stmt->execute($args);
Looks like you've got a few good options for how to do it in SQL, or how to make the SQL string variable in PHP.
One reason to consider using an 'if' in the PHP code for the database access performance.
When you introduce an 'or' condition like that in SQL, you're not going to get index access. It is much harder for the database to determine what path it should take than for the PHP code because the SQL engine optimizes the query without knowing what the variable will resolve to at execution.
You already know in the PHP which version of the query you really want. This will perform better if you make that choice there.
This will work if you pass an occupation or a NULL value.
SELECT *
FROM TDdb
WHERE status = $status
AND ($occupation IS NULL OR occupation = $occupation)
"SELECT * FROM TDdb WHERE status = '$status' AND (occupation = '$occupation' OR occupation IS NULL)";
Apart from the solution provided by #Tom and #Damien Legros, you may create two query strings one with occupation and one without occupation. Something like:
$query = "SELECT * FROM TDdb WHERE status = $status";
if ($occupation != "") {
/*When you have value for occupation*/
$query .= " AND occupation =$occupation";
}
So in this case, data will be returned if you have only the status field. Secondly, please check if the status and occupation fields in table are varchar then you have to enclose them in single quotes (').
Thanks everyone for help. specially jack.
finally i created my query like this:
$query = 'SELECT * FROM TDdb';
if ($status) {
$query = $query." WHERE status = '".$status."'";
}
if ($occupation) {
$query = $query." AND occupation = '".$occupation."'";
}

PHP Patterns - how can I write this code?

I want to make an category-system CMS. Everything is fine, except a big trouble.
How can I can handle and generate the mysql query depends by some inputs like:
site.com/some-category&sortby=views&from=smt&anotherInput=key
For example, for this input my query should be something like
SELECT * FROM `articles` WHERE from='smt' AND afield='key' ORDER BY VIEWS
But these inputs will be different. How I can write this code? I don't know much things about designs patterns, but, I've heard about Factory pattern, is this a part of my solution?
Than
Factory pattern can help you with e.g. connecting/quering various databases without need to rewrite the entire code. This has nothing to do about query itself.
You can look at PDO extension, I usually use it together with prepared statements.
It will let you write queries like this:
$prepare = $db->prepare('
SELECT
*
FROM
articles
WHERE
from=:from AND afield=:afield
ORDER BY
views
');
$prepare->bindValue(':from', $_GET['from'], PDO::PARAM_STR);
$prepare->bindValue(':afield', $_GET['afield'], PDO::PARAM_STR);
$prepare->execute();
return $prepare;
The good thing about it is that you don't need to protect this from sql injections as PDO makes it for you. Also, the query is cached and you can run it several times with different params.
Very bad practice to use raw GET params in query directly, i.e. you shouldn't make constructions like
SELECT * FROM articles WHERE from=$_GET['from'] AND afield='key' ORDER BY VIEWS
but instead something like
if ($_GET['from'] == 'smt') $from = 'smt'
SELECT * FROM articles WHERE from='$from' AND afield='key' ORDER BY VIEWS
and so on
P.S. keyword is 'sql injection'
You can build the query string as pieces depending on what you need:
$query = "SELECT * FROM `articles` WHERE 1 = 1";
$where = ''
if (isset($_GET['from'])) {
$where .= " AND `from` = '" . mysql_real_escape_string($_GET['from']) . "'"
}
if (isset($_GET['anotherInput'])) {
$where .= " AND `from` = '" . mysql_real_escape_string($_GET['anotherInput']) . "'"
}
if (isset($_GET['sortby'] == 'views') {
$orderby = " ORDER BY `views` DESC"
} else {
$orderby = " ORDER BY `id` DESC"
}
$query = $query . $where . $orderby;
$result = mysql_query($query);
This is sort of the straight PHP/MySQL way, but I actually do suggest that you use prepared statements as in Pavel Dubinin's answer.
This has nothing to do with patterns. Use the $_GET superglobal variable to dynamically generate your query string.
$query = "SELECT * FROM articles WHERE from='".
$_GET['from'].
"' AND afield='".
$_GET['anotherInput'].
"' ORDER BY ".
$_GET['sortby'];
Disclaimer: This is prone to SQL injection. Use input escaping and prepared statements, ex PDO, in a production environment like:
$query = "SELECT * FROM articles WHERE from='?' AND afield='?' ORDER BY ?";
$clean_from = htmlentities($_POST['from'], ENT_QUOTES, 'UTF-8');
$clean_anotherInput = htmlentities($_POST['anotherInput'], ENT_QUOTES, 'UTF-8');
$clean_sortby = htmlentities($_POST['sortby'], ENT_QUOTES, 'UTF-8');
$clean_inputs = array($clean_from, $clean_anotherInput, $clean_sortby);
$sth = $dbh->prepare($query);
$sth->execute($clean_inputs);

how to build a sql query using the content of a variable

I'm trying to build a query using php and mysql,
$query = "select * from products where product_name = '$item_name'";
this works when $item_name holds only one name, but $item_name is an array and based on the user's interaction can contain multiple names, how can I make the query to run for multiple name and get the resulted rows.
Thanks in advance
Here's how you could build a safe list of names for inserting into an IN clause...
if (is_array($names) && count($names))
{
$filter="('".implode("','" array_map('mysql_real_escape_string', $names))."')";
$sql="select * from products where product_name in $filter";
//go fetch the results
}
else
{
//input was empty or not an array - you might want to throw an
//an error, or show 'no results'
}
array_map returns the input array of names after running each name through mysql_real_escape_string to sanitize it. We implode that array to make a nice list to use with an IN clause.
You should always ensure any data, particularly coming directly from the client side, is properly escaped in a query to prevent SQL injection attacks.
$vals = implode(',',$item_name);
$query = "select * from products where product_name in (".$vals.");";
Give that a try.
$query = "select * from products where product_name in(";
foreach($item_name as $name)
{
$query .= "'" . $item_name . "', ";
}
$query = substr($query, 0, strlen$query) - 2);
$query .= ");";
First answer (by inkedmn) is really the best one though
foreach($item_name as $name) {
$query = "select * from products where product_name = '$name'";
//whatever you want to do with the query here
}
something like that ought to do it.
Based on inkedmn's response (which didn't quote the item names):
$query = 'select * from products where product_name in ("' . implode('", "', $item_name ) . '")';
Although you may be better with a fulltext search.
http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.html

Categories