Simplifying mysql filter query - php

I'm building a platform for a casting manager to catalog Actors and be able to browse them. My table 'actor' is set up with first name, last name, email, phone, address etc.
I have a browse.php page which has a form to filter results. Here's my class that I need help simplifying as well as getting rid of the wild card result when a field is null.
I pass through the form data into an array, $search, and the class checks if the array section is filled and writes to the SQL query.
public function getActors($search) {
if(isset($search)) {
if($search["first_name"] == NULL) { $first_name = "LIKE '%'"; } else { $first_name = "LIKE '".$search["first_name"]."'"; }
if($search["last_name"] == NULL) { $last_name = "LIKE '%'"; } else { $last_name = "LIKE '".$search["last_name"]."'"; }
if($search["gender"] == NULL) { $gender = "LIKE '%'"; } else { $gender = " = '".$search["gender"]."'"; }
if($search["address_state"] == NULL) { $address_state = "LIKE '%'"; } else { $address_state = " = '".$search["address_state"]."'"; }
if($search["ethnicity"] == NULL) { $ethnicity = "LIKE '%'"; } else { $ethnicity = " = '".$search["ethnicity"]."'"; }
if($search["status"] == NULL) { $status = "LIKE '%'"; } else { $status = " = '".$search["status"]."'"; }
$sql = "SELECT * FROM actor WHERE
first_name ".$first_name." AND
last_name ".$last_name." AND
gender ".$gender." AND
address_state ".$address_state." AND
ethnicity ".$ethnicity." AND
status ".$status."
";
} else {
$sql = "SELECT * FROM actor";
}
$s = mysql_query($sql) or die (mysql_error());
$numrows = mysql_num_rows($s);
for($x=0; $x < $numrows; $x++){
$actorArray[$x] = mysql_fetch_row($s);
}
return $actorArray;
}
Any help on simplifying this or suggestions?

for the conditions, I you can use a foreach loop.
if(isset($search)) {
$conditions = array();
foreach($search as $k => $criteria){
if ($criteria != NULL){
$condition[] = "{$k} LIKE '{$criteria}'";
//this will produce for $search['first_name'] = 'john'
// "first_name LIKE 'john'"
}
}
//we transform the array of conditions into a string
$conditions = implode (' AND ', $conditions);
$sql = "SELECT * FROM actor WHERE " . $conditions;
}else{
$sql = "SELECT * FROM actor";
}

What about (within the isset block)...
$fields = array('first_name','last_name','gender','address_state','ethnicity','status');
$parts = array();
foreach($fields as $field) {
if(!empty($search[$field])) {
$parts[] = $field . ' LIKE "' . $search[$field] . '"';
}
}
$sql = "SELECT * FROM actor WHERE " . implode(' AND ', $parts);
And as mentioned by #Dvir, it's better to use positional parameters in your SQL statements.

LIKE '%'? seriously? why not just don't include the specific clause if it's null?
Also, your query is vulnerable to SQL injections.
After reading about SQL injections, you can just add the WHERE clauses by going over the $search array, adding the specific clause, and binding the parameter.

Related

Need to keep blank field with the data on the table

So I'm trying to have the user update this table, but if the field is left blank i'd like the data to be left alone, not change it to a blank field or null, any ideas?
<?
elseif ($Code == "U")
{
$sql = "UPDATE movieDATA SET Name = '$Name', Genre = '$Genre', Starring = '$Starring', Year = '$Year', BoxOffice = '$BoxOffice' where IDNO = '$idno'";
$result= mysqli_query($link,$sql) or die(mysqli_error($link));
$showresult = mysqli_query($link,"SELECT * from movieDATA") or die("Invalid query: " . mysqli_error($link));
while ($row = mysqli_fetch_array($showresult))
{
echo ("<br> ID = ". $row["IDNO"] . "<br> NAME = " . $row["Name"] . "<br>");
echo("Genre = " . $row["Genre"] . "<br> Starring = " . $row["Starring"] . "<br>");
echo("Year = " . $row["Year"] . "<br> Box Office = " . $row["BoxOffice"] . "<br>");
}
}
?>
$fields = array(); // Take a blank array of fields and values.
$Name = trim($Name); // Trim the variable, user may add only spaces
$Genre = trim($Genre); // Do this for all variables.
$Starring = trim($Starring);
$Year = trim($Year);
$BoxOffice = trim($BoxOffice);
if (! empty($Name)) { // If user has filled the field, append to array.
$fields[] = "Name = '$Name'";
}
if (! empty($Genre)) {
$fields[] = "Name = '$Genre'";
}
if (! empty($Starring)) {
$fields[] = "Name = '$Starring'";
}
if (! empty($Year)) {
$fields[] = "Name = '$Year'";
}
if (! empty($BoxOffice)) {
$fields[] = "Name = '$BoxOffice'";
}
if (! empty($fields)) { // If the array is not empty, go for Query.
$sql = "UPDATE movieDATA SET "; // If user has not added any field value,
$sql .= implode(', ', $fields); // no SQL Query will be fired.
$sql .= " WHERE IDNO = '$idno'";
}
Your requirement:
Not to update the fields which user has left blank.
Solution:
Add if condition to check if every field is filled up.
One way to do this:
$q_set = [];
if (!empty($Name)) {
$q_set []= "Name = '$Name'";
}
if (!empty($Genre)) {
$q_set []= "Genre = '$Genre'";
}
/* ... */
if (!empty($q_set)) {
$sql = "UPDATE movieDATA SET " . implode(',', $q_set)
. " WHERE IDNO = '$idno'";
}
Note, that the variables passed into SQL should be escaped

search query in php

I am creating search query in php by passing variable through GET method. When the variable is null then it's passing the query like,
SELECT * FROM table WHERE column_name = null.
And it's showing error (obvious). I want to create query like. If user don't select anything from search options then it should fetch all the data from that column.
What's the correct logic for that?
Thanks.
Code:
if(isset($_GET['selPetType']) && $_GET['selPetType'] != '')
{
$searchParams['petType'] = $_GET['selPetType'];
$queryStr .= " PetType='" .$_GET['selPetType']. "'";
}
if(isset($_GET['txtPetBreed1']) && !empty($_GET['txtPetBreed1']))
{
$searchParams['breed'] = $_GET['txtPetBreed1'];
$queryStr .= " AND PetBreed1 ='". $_GET['txtPetBreed1'] . "'";
}
$clause1 = "SELECT * FROM pet WHERE $queryStr ORDER BY `Avatar` ASC LIMIT $startLimit, $pageLimit";
$totalRun1 = $allQuery->run($clause1);
Maybe something like this:
$get['param1'] = 'foo';
$get['param3'] = null;
$get['param2'] = '';
$get['param4'] = 'bar';
$where = null;
foreach ($get as $col => $val) {
if (!empty($val)) {
$where[] = $col . ' = "' . $val . '"';
}
}
$select = 'SELECT * FROM pet ';
if ($where) {
$select .= 'WHERE ' . implode(' AND ', $where);
}
$select .= ' ORDER BY `Avatar` ASC LIMIT $startLimit, $pageLimit';
Edit: I added if to remove empty values and added 2 new values to example so you can see this values will not be in query.
if(isset($_GET['your_variable'])){
$whr = "column_name = $_GET['your_variable']";
}
else{
$whr = "1 = 1";
}
$qry ="SELECT * FROM table WHERE ".$whr;
For example :
<?php
$userSelectedValue = ...;
$whereCondition = $userSelectedValue ? " AND column_name = " . $userSelectedValue : "" ;
$query = "SELECT * FROM table WHERE 1" . $whereCondition;
?>
Then consider it's more safe to use prepared statements.

making a better search query in php and mysql

I'm trying to create a search query:
I'm giving 6 options to search.
Bedrooms
Type
Postcode
Location
Min price
Max price
I have these fields in a form. I searched a lot but couldn't find the answer I was searching. I tried queries using LIKE and % too. But that didn't worked out too.
If a user selects only 'Type' then all of the data with that type should be displayed. And the same goes to other fields.
And again, if a user selects 2 or 3 options and searches then the results which match the options selected should be displayed.
How can I create a search like this? Should I do?:
if(){
}else if(){
}
You can build your sql query on the fly. If search value is not empty (or something else that does not count as a search value) then do not add search.
Do not forget to add mysql_real_escape_string to a params or bad people will exploit your software.
exampe in php:
<?php
$params = array('type' => 'aaa', 'max_price'=>100); // parameters that a user gave. Example from $_POST or $_GET
$querySearch = array();
if(isset($params['type'])) {
$querySearch[] = "type LIKE '%".mysql_real_escape_string($params['type'])."%'";
}
if(isset($params['max_price'])) {
$querySearch[] = "price <= ".mysql_real_escape_string($params['max_price']);
}
if(isset($params['min_price'])) {
$querySearch[] = "price >= ".mysql_real_escape_string($params['min_price']);
}
// and etc.
$q = 'select * FROM hotel WHERE ' . implode(' AND ' , $querySearch);
echo $q;
?>
then you can use query $q to do db select.
dynamically build the query
$useAnd = false;
$ query = " select * from table";
if (isset($bedrooms) == true or isset($type) == true or isset($postcode)==true or ...)
{
$query = $query. " where ";
if (isset($bedroomsIsset) = true)
{
$query = $query . "bedrooms >=". $bedrooms; $useAnd=true;
}
if (isset($type) = true)
{
if ($useAnd=true)
{$query = $query . " and " ;}
$query = $query . "type =". $type; $useAnd=true;
}
if (isset($postcode)==true)
{
if (isset($poscode) = true)
{
if ($useAnd=true)
{$query = $query . " and " ;}
$query = $query . "postcode =". $postcode; $useAnd=true;
}
if (...)
}
if(!empty($some_option)) $search_options["option_name"] = $some_option;
$query = "some query";
$where = "";
if(!empty($search_options)){
$first_option = array_shift($search_types);
$where = " " . key($first_option) . " = " . $first_option;
foreach($search_options as $key => $option){
$where .= " AND $key = $option";
}
}
$query .= $where;

PHP navigation with filters

I am working out a faceted navigation (I think that's the right expression...)
So I have a lot of categories and manufacturers on which a user can filter.
I came to the point where I have to get the results from the filters from my database. What would the fastest way to create these queries? I have 3 get values that I can filter on (manufacturer/company/category) so that would mean i would write a query for when manufacturer & company is an active filter and for category and company etc... I see how much work this is and I wonder if there is a short way to do this?
probably want something like below (if I understand your question correctly:
SELECT * FROM tablename WHERE manufacturer='A' AND company='B' AND category='C'
If you're using PHP, you could use it to put the current value in for A, B, and C - but remember to sanitize these values
Edit
For example, with PHP...
<?php
$manufacturer = mysql_real_escape_string($_GET['manufacturer']);
$company = mysql_real_escape_string($_GET['company']);
$category = mysql_real_escape_string($_GET['category']);
$query = "SELECT * FROM tablename WHERE manufacturer='".$manufacturer."' AND company='".$company."' AND category='".$category."'";
// then simply run the query....
?>
Edit 2
You can change AND to OR when needed be
<?php
$query = "SELECT * FROM tablename";
$mixed_query = "";
if(isset($_GET['manufacturer']) && !empty($_GET['manufacturer'])){
$mixed_query .= ($mixed_query !== "") ? " AND " : " WHERE ";
$mixed_query .= "manufacturer='".mysql_real_escape_string($_GET['manufacturer'])."'";
}
if(isset($_GET['company']) && !empty($_GET['company'])){
$mixed_query .= ($mixed_query !== "") ? " AND " : " WHERE ";
$mixed_query .= "company='".mysql_real_escape_string($_GET['company'])."'";
}
if(isset($_GET['category']) && !empty($_GET['category'])){
$mixed_query .= ($mixed_query !== "") ? " AND " : " WHERE ";
$mixed_query .= "category='".mysql_real_escape_string($_GET['category'])."'";
}
// then add to query
$query .= $mixed_query;
// then simply run the query....
?>
The simplest solution would probably be one where you build the query dynamically:
// GET SANITIZED $manufacturer $company $category
// Initialize the array
$facets = array();
if (isset($manufacturer))
{
$facets[] = "manufacturer = '$manufacturer'";
}
if (isset($company))
{
$facets[] = "company = '$company'";
}
if (isset($category))
{
$facets[] = "category = '$category'";
}
$query = "SELECT * FROM table";
if (count($facets) > 0)
{
$query .= " WHERE" . implode(" AND ", $facets);
}
Your query would only filter on those facets that are set.
To make it slightly more general:
// GET SANITIZED $manufacturer $company $category
// Initialize the array
$facets["manufacturer"] = $manufacturer;
$facets["company"] = $company;
$facets["category"] = $category;
// ADD MORE AS NECESSARY
foreach($facets as $key=>$value)
{
if ($value != '')
{
$where[] = "$key = '$value'";
}
}
$query = "SELECT * FROM table";
if (count($where) > 0)
{
$query .= " WHERE" . implode(" AND ", $where);
}

SQL Multiple WHERE Clause Problem

I'm attempting the modify this Modx Snippet so that it will accept multiple values being returned from the db instead of the default one.
tvTags, by default, was only meant to be set to one variable. I modified it a bit so that it's exploded into a list of variables. I'd like to query the database for each of these variables and return the tags associated with each. However, I'm having difficulty as I'm fairly new to SQL and PHP.
I plugged in $region and it works, but I'm not really sure how to add in more WHERE clauses for the $countries variable.
Thanks for your help!
if (!function_exists('getTags')) {
function getTags($cIDs, $tvTags, $days) {
global $modx, $parent;
$docTags = array ();
$baspath= $modx->config["base_path"] . "manager/includes";
include_once $baspath . "/tmplvars.format.inc.php";
include_once $baspath . "/tmplvars.commands.inc.php";
if ($days > 0) {
$pub_date = mktime() - $days*24*60*60;
} else {
$pub_date = 0;
}
list($region, $countries) = explode(",", $tvTags);
$tb1 = $modx->getFullTableName("site_tmplvar_contentvalues");
$tb2 = $modx->getFullTableName("site_tmplvars");
$tb_content = $modx->getFullTableName("site_content");
$query = "SELECT stv.name,stc.tmplvarid,stc.contentid,stv.type,stv.display,stv.display_params,stc.value";
$query .= " FROM ".$tb1." stc LEFT JOIN ".$tb2." stv ON stv.id=stc.tmplvarid ";
$query .= " LEFT JOIN $tb_content tb_content ON stc.contentid=tb_content.id ";
$query .= " WHERE stv.name='".$region."' AND stc.contentid IN (".implode($cIDs,",").") ";
$query .= " AND tb_content.pub_date >= '$pub_date' ";
$query .= " AND tb_content.published = 1 ";
$query .= " ORDER BY stc.contentid ASC;";
$rs = $modx->db->query($query);
$tot = $modx->db->getRecordCount($rs);
$resourceArray = array();
for($i=0;$i<$tot;$i++) {
$row = #$modx->fetchRow($rs);
$docTags[$row['contentid']]['tags'] = getTVDisplayFormat($row['name'], $row['value'], $row['display'], $row['display_params'], $row['type'],$row['contentid']);
}
if ($tot != count($cIDs)) {
$query = "SELECT name,type,display,display_params,default_text";
$query .= " FROM $tb2";
$query .= " WHERE name='".$region."' LIMIT 1";
$rs = $modx->db->query($query);
$row = #$modx->fetchRow($rs);
$defaultOutput = getTVDisplayFormat($row['name'], $row['default_text'], $row['display'], $row['display_params'], $row['type'],$row['contentid']);
foreach ($cIDs as $id) {
if (!isset($docTags[$id]['tags'])) {
$docTags[$id]['tags'] = $defaultOutput;
}
}
}
return $docTags;
}
}
You don't add in more WHERE clauses, you use ANDs and ORs in the already existing where clause. I would say after the line $query .= " WHERE stv.name = '".$region... you put in
foreach ($countries as $country)
{
$query .= "OR stv.name = '{$country}', ";
}
but I don't know how you want the query to work.

Categories