I have a standard code to search by column and am now trying to add the option of searching multiple criteria in one column.
Currently I can search by one criteria, so if the user selects location QLD it will display all QLD entries, what changes do i need to make to enable the user to search both for location QLD and NSW?
I have updated the element to be multiple, but am not sure how to adjust the PHP and MySQL to process multiple criteria.
Can someone help?
Thanks,
sbgmedia
<?php
$condition = '';
if(isset($_REQUEST['Location']) and $_REQUEST['Location']!=""){
$condition .= ' AND Location LIKE "%'.$_REQUEST['Location'].'%" ';
}
$userData = $db->getAllRecords('candidates','*',$condition,'ORDER BY id ASC');
?>
<select name="Location[]" id="Location" class="form-control" value="<?php echo isset($_REQUEST['Location'])?$_REQUEST['Location']:''?>" multiple>
<option value="" <?php if(isset($_REQUEST['Location']) && $_REQUEST['Location'] == '')
echo ' selected="selected"';?></option>
<option value="ACT" <?php if(isset($_REQUEST['Location']) && $_REQUEST['Location'] == 'ACT')
echo ' selected="selected"';?>ACT</option>
<option value="NSW" <?php if(isset($_REQUEST['Location']) && $_REQUEST['Location'] == 'NSW')
echo ' selected="selected"';?>NSW</option>
<option value="QLD" <?php if(isset($_REQUEST['Location']) && $_REQUEST['Location'] == 'QLD')
echo ' selected="selected"';?>QLD</option>
</select>
If the Locations are represented one-to-one, you can use IN to search, like so:
SELECT * FROM candidates WHERE Location IN ('QLD', 'NSW');
If the Locations are just part of the string, you can compare with OR in your query, like so:
SELECT * FROM candidates WHERE Location LIKE '%QLD%' OR Location LIKE '%NSW%';
To represent a solution, based on your own code, I'll try and fit it in using IN and replacing $_REQUEST with $_POST (because control over your HTTP methods is more secure).
<?php
$condition = '';
if(!empty($_POST['Location')){
$condition .= " AND Location IN ('" . implode("', '", $_POST['Location']) ."')";
}
$userData = $db->getAllRecords('candidates','*',$condition,'ORDER BY id ASC');
?>
Please be ware that this is just an example! Your code is open to SQL injection which you should address ASAP!
Without knowing what abstraction layer $db is, I can only urge you to look into "sql injection" and "mysql prepared statements" on your favorite search engine.
I have a form which has select options for age and radiobuttons for gender. The idea is that the form can be used to search for a specific user by age and gender.
Currently, the form sometimes executes the header (see below) and sometimes not. So Assume, I am logged in as Conor, Conor specifies that he wants to search for a user aged between 20-21 and is male. Upon clicking submit, sometimes the form will find someone, sometimes it will not. I want the query to keep running until a user is found, unless no one exists in the database.
In this case, the header should be executed, taking the user to messages.php because a male aged 20 exists in the database.
Here is my approach:
Form:
<form action="random_chat.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="age_from" id="age_from" value="0"/>
<input type="hidden" name="age_to" id="age_to" value="50"/>
<label for="amount">Age:</label>
from:
<select name="age_from" id="age_a" onchange="checkages_a()">
<option value="none"></option>
<?php
for($i = 17; $i <= 50; ++$i) {
echo "\t", '<option value="', $i. '">', $i, '</option>', "\n";
}
?>
</select>
to:
<select name="age_to" id="age_b" onchange="checkages_b()">
<option value="none"></option>
<?php
for($i = 18; $i <= 50; ++$i) {
echo "\t", '<option value="', $i, '">', $i, '</option>', "\n";
}
?>
</select>
<!-- I have input type submit above the radio buttons due to table layout -->
<input type="submit" class="btn btn-info" name="submit" value="Click to start chat! " />
<label for="amount">Gender:</label>
<input type="radio" name="gender" value="male">Male</input> <br />
<input type="radio" name="gender" value="female">Female</input><br />
<input type="radio" name="gender" value="any">Any</input>
</form>
PHP code processing the form:
<?php
$refined_gender = htmlentities (strip_tags(#$_POST['gender']));
$age_from = htmlentities (strip_tags(#$_POST['age_from']));
$age_to = htmlentities (strip_tags(#$_POST['age_to']));
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
if (isset($_POST['submit'])){
// if age parameter used...
$defined_chat = mysqli_prepare ($connect, "SELECT * FROM users WHERE gender =? AND age BETWEEN ? AND ? ORDER BY RAND() LIMIT 1");
mysqli_stmt_bind_param($defined_chat, "sss", $refined_gender, $age_from, $age_to);
mysqli_stmt_execute ($defined_chat);
while ($get_user = mysqli_fetch_assoc($defined_chat)){
$rand_name = $get_user['username'];
$acc_type = $get_user['account_type'];
if ($acc_type != "admin" ){
// if the name genereated by db is same as logged in users name, then run query again until name is found.
if ($rand_name == $username){
$defined_chat;
} else {
header ("Location: /messages.php?u=$rand_name");
}
} else {
echo "No user found fitting those requirements.";
}
} // while closed
mysqli_stmt_close($defined_chat);
}
?>
I have tried to change the form action to '#', thinking it may be just be refreshing the page, but it didn't work.
Also, how can I make this so that even if one parameter is filled, then still execute search? For example, if I search for a male, with no age defined, it will find a male user. If I search for someone ages between 26-31 and no gender defined, then still execute header?
Edit:
$username is the session variable, which is defined at the very start of random_chat.php.
Do not rely on the value of a submit button to determine if your form was submitted or not. This will not work on all browsers, especially older ones, this value is not always passed back to the server, instead just look at any value inside the form to verify if submission has occurred, or the existence of $_POST in general.
At first sight, what you are attending to do looks to me simpler than the way you are actually trying to achieve it.
Construction you SQL query correctly may be the only thing complicated in here.
Only changing your query could actually already remove your need of the if/else for the account_type and the if/else to check if the current user is the same as the queried one :
$sql = "SELECT
*
FROM
users
WHERE
gender like ? AND
age BETWEEN ? AND ? AND
# with this condition you do not need to test if the user logged is the queried one
username != ? AND
# and with this one, you do not care about exclude adimn either
account_type != 'admin'
ORDER BY RAND()
LIMIT 1";
$defined_chat = mysqli_prepare (
$connect, $sql
);
mysqli_stmt_bind_param(
$defined_chat,
"ssss",
$refined_gender,
$age_from,
$age_to,
$username
);
Then about the fact that you want to be able to search even without any selection on both gender and age, you can use a combinaison of the wildcard % of SQL, the operator like and the ternary operator of PHP (you did maybe already see that I changed gender =? to gender like ? in the query above).
// Means if gender is different than 'any', it will assign the posted value to the variable, otherwise, it will assign the sql wildcard %
$refined_gender = (htmlentities (strip_tags(#$_POST['gender'])) != 'any' ? htmlentities (strip_tags(#$_POST['gender'])) : '%');
// Means if age is different than 'none', it will assign the posted value to the variable, otherwise, it will assign the lowest possible age, 0
$age_from = (htmlentities (strip_tags(#$_POST['age_from'])) != 'none' ? htmlentities (strip_tags(#$_POST['age_from'])) : '0');
// Means if age is different than 'none', it will assign the posted value to the variable, otherwise, it will assign an age bigger than anyone could attain, 9999
$age_to = (htmlentities (strip_tags(#$_POST['age_to'])) != 'none' ? htmlentities (strip_tags(#$_POST['age_to'])) : '9999');
see ternary operators in PHP doc
and see MySQL like and wildcard usage
All in one, your processing PHP script could look like this :
$refined_gender = (htmlentities (strip_tags(#$_POST['gender'])) != 'any' ? htmlentities (strip_tags(#$_POST['gender'])) : '%');
$age_from = (htmlentities (strip_tags(#$_POST['age_from'])) != 'none' ? htmlentities (strip_tags(#$_POST['age_from'])) : '0');
$age_to = (htmlentities (strip_tags(#$_POST['age_to'])) != 'none' ? htmlentities (strip_tags(#$_POST['age_to'])) : '9999');
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
if (isset($_POST['submit'])){
$sql = "SELECT
*
FROM
users
WHERE
gender like ? AND
age BETWEEN ? AND ? AND
# with this condition you do not need to test if the user logged is the queried one
username != ? AND
# and with this one, you do not care about exclude adimn either
account_type != 'admin'
ORDER BY RAND()
LIMIT 1";
$defined_chat = mysqli_prepare (
$connect, $sql
);
mysqli_stmt_bind_param(
$defined_chat,
"ssss",
$refined_gender,
$age_from,
$age_to,
$username
);
mysqli_stmt_execute ($defined_chat);
while ($get_user = mysqli_fetch_assoc($defined_chat)){
$rand_name = $get_user['username'];
header ("Location: /messages.php?u=$rand_name");
} // while closed
echo "No user found fitting those requirements.";
mysqli_stmt_close($defined_chat);
}
You have some mixed logic, so some explanations might help.
1) header('location: ...') will tell the browser to reload the page to the new location. This does not appear to be what you want - you just want to continue execution? NOTE: You should also [nearly] always have "exit();" after a header('location: ... '); line otherwise execution continues which is [nearly] never what you want!)
2) a while loop will continue "while" the condition is true. So the loop continues while there are rows being returned.
3) Running the query again will not return anything new - you can use the same results. So just skip over until you find the result you need!
So, written in English, what you want to do after running the DB query is:
set a tally count to zero
while we have some rows coming from the db {
if that row is not admin {
if that row does not match the current user {
show the result
increase tally count
}
}
}
if tally count is zero {
say "no entries found"
}
So, in code, this is
$foundUsers = 0;
while ($get_user = mysqli_fetch_assoc($defined_chat)){
$rand_name = $get_user['username'];
$acc_type = $get_user['account_type'];
if ($acc_type !== "admin" ){
// if the name genereated by db is same as logged in users name, then run query again until name is found.
if ($rand_name !== $username) {
$foundUsers = $foundUsers + 1; // Or $foundUsers++ for short
echo 'Matched User: ' . $rand_name . '<br>';
}
}
} // while closed
if ($foundUsers == 0) {
echo "No user found fitting those requirements.";
}
Ok, first of all, if you want to exclude a parameter from the query, you're going to have to build some logic to exclude that variable.
So if $refined_gender = "any", then you need to exclude it from the query. I would change your combobox default values to:
<select name="age_from" id="age_a" onchange="checkages_a()">
<option value="-1"></option>
<?php
for($i = 17; $i <= 50; ++$i) {
echo "\t", '<option value="', $i. '">', $i, '</option>', "\n";
}
?>
</select>
to:
<select name="age_to" id="age_b" onchange="checkages_b()">
<option value="999"></option>
<?php
for($i = 18; $i <= 50; ++$i) {
echo "\t", '<option value="', $i, '">', $i, '</option>', "\n";
}
?>
</select>
Then, now you've fixed the age between, to filter the gender out. Also, I've added a clause to your WHERE clause: AND account_type != 'admin', this will filter out the admins accounts on the SQL side rather than checking on the PHP side.
// If gender is specified, query gender
if($refined_gender !== "any"){
$defined_chat = mysqli_prepare ($connect, "SELECT * FROM users WHERE gender =? AND age BETWEEN ? AND ? AND account_type != 'admin' ORDER BY RAND() LIMIT 1");
mysqli_stmt_bind_param($defined_chat, "sii", $refined_gender, $age_from, $age_to);
} else {
$defined_chat = mysqli_prepare ($connect, "SELECT * FROM users WHERE age BETWEEN ? AND ? AND account_type != 'admin' ORDER BY RAND() LIMIT 1");
mysqli_stmt_bind_param($defined_chat, "ii", $age_from, $age_to);
}
mysqli_stmt_execute ($defined_chat);
Suggestion #1: Possible race condition see note in code.
if ($acc_type != "admin" ){
// if the name genereated by db is same as logged in users name, then run query again until name is found.
if ($rand_name == $username){
$defined_chat;<-- don't you need to re-execute this? Seems like you are hitting a race condition since the statement result will never change
} else {
header ("Location: /messages.php?u=$rand_name");
}
} else {
echo "No user found fitting those requirements.";
}
Suggestion #2:
Outside of that you should be sure you aren't getting the current user with a
WHERE name NOT LIKE '%?%' up front in the initial query and get rid of that if statement.
Suggestion #3:
Or better, use the user IDs. What if there's another user with the same name as the searcher, but they're a different person? Base the current user match on UID, not name.
Suggestion #4:
You should absolutely almost never run a select query/statment inside a PHP (or any scripting language) loop. There's always a better way. Filter your data in the database where it's efficient. Even for inserts you can do a single bulk insert much more efficiently than a bunch of insert queries.
I have a MySQL database, and the table I need to work with has 9 columns of information. My goal is to be able to filter, based on two arguments. For instance, the table is about students so it has data for first name, last name, id, course they are signed up for, status, occupation age and another 2 fields that are not that important. I need to be able to filter, based on the student's status and/or the course.
So far, I managed to get the php work done, with a form and a select tag, to filter based on status, but I have no idea how to add the second part. The done thing should be able to filter, based on status only, based on course only, or based on the selected status and course. The code looks like this:
if (isset($_POST['filter'])) {
$search_term = mysqli_real_escape_string($conn, $_POST['filter_status']);
$q .= " WHERE status = '$search_term'";
}
echo $q;
<form method="POST" action="index.php">
<select name="filter_status" >
<option value="confirmed">confirmed</option>
<option value="declined">declined</option>
<option value="rejected">rejected</option>
<option value="pending">pending</option>
<option value="unconfirmed">unconfirmed</option>
</select>
<input type="submit" name="filter">
</form>
This works correctly, I have it a second time for the second criteria, but they don't work together.
try to change,
$q .= " WHERE status = '$search_term'";
to
$q .= " WHERE CONCAT_WS(',',status,course) like %'$search_term'%";
you can add as many columns after course.
$filter_status = $_POST['filter_status'];
$course = $_POST['course'];
$where = 'WHERE 1';
$where .= $filter_status ? " AND status = {$filter_status}" : '';
$where .= $course ? " AND course = {$course}" : '';
Did you mean this? when user select course and filter_status use this two conditions, on the other hand use one of conditions which is being selected.
The WHERE 1 will always be TRUE, so it can be followed by AND statements
Use the term AND or OR in your query after WHERE
WHERE status = '$search_term' AND course = '$something'
Thank you all for your input. It helped nudge me in the right direction. The code that ended up doing what I needed is as follows. It's not very elegant, but it does the job well:
$q = "SELECT *
FROM students";
if (isset($_POST['filter'])) {
if ($_POST['filter_status'] == null) {
$search_term2 = mysqli_real_escape_string($conn, $_POST['filter_course']);
$q .= " WHERE course = '$search_term2'";
} elseif ($_POST['filter_course'] == null) {
$search_term = mysqli_real_escape_string($conn, $_POST['filter_status']);
$q .= " WHERE status = '$search_term'";
} else {
$search_term = mysqli_real_escape_string($conn, $_POST['filter_status']);
$search_term2 = mysqli_real_escape_string($conn, $_POST['filter_course']);
$q .= " WHERE status = '$search_term' AND course = '$search_term2'";
}
}
And the form:
<form method="POST" action="index.php">
<select name="filter_status" >
<option value= ""></option>
<option value="confirmed">confirmed</option>
<option value="declined">declined</option>
<option value="rejected">rejected</option>
<option value="pending">pending</option>
<option value="unconfirmed">unconfirmed</option>
</select>
<select name="filter_course">
<option value= ""></option>
<option value="php">php</option>
<option value="java">java</option>
</select>
<input type="submit" name="filter">
</form>
I get confused for post variable to sql query,
here is sample of my report.php code
<form action="report.php">
<select id="status" name="status">
<option value="MARRIED">married</option>
<option value="SINGLE">Single</option>
<option value="ALL">ALL</option>
</select>
<input type="submit" value="Seach">
</form>
<?php
$status= $_GET['status'];
// Create DB connection
$sql = "SELECT * FROM member WHERE status ='$status'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "<B>id: </B>" . $row["user_id"]. " -- <b>Date Record:</b> " . $row["created"]. " -- <b>Last Seen</b> " . $row["last_seen"]. " -- <b>Status: </b> "
}
} else {
echo "0 results";
}
$conn->close();
?>
How do i Query If "ALL" condition is Selected?
I dont know the PHP so this is not the exact code but concept should be like this
if( $status == 'ALL' )
$sql = "SELECT * FROM member";
else
$sql = "SELECT * FROM member WHERE status ='$status'";
It would be very wise in this case to store the $status variable in POST instead, since the SQL query depends on what value is stored in the URL, and is thus exposed to the user.
Another thing, since you are dealing with legacy code here is to make extra sure that you filter the user input and SQL query as much as possible. The thing with using older and obsolete functionality is that you will still be vulnerable to XSS and SQL injection attacks regardless of the precautions you take so it is highly recommended you go with either the MySQLi or PDO (PHP Data Objects) extension instead as these offer more stable and advanced functionality.
$status = htmlspecialchars($_GET['status'], ENT_QUOTES);
$where = '';
if ($status != 'ALL') {
$where = 'WHERE status = "$status"';
}
$sql = mysql_real_escape_string('SELECT * FROM member ' . $where);
$results = mysql_query($sql);
In PHP file
<?php
$status= $_GET['status'];
if($status == 'ALL'){
$where = '';
}else{
$where = 'status = '".$status."' ';
}
// Create DB connection
$sql = "SELECT * FROM member WHERE ".$where." ";
?>
I have made a HTML search form which creates a query to a MySql database based on the contents of a form. What I would love to do is ignore the search parameter if the user leaves that specific form field empty. There are lots of answers online, especially on this website, but I can't get any of them to work.
I have stripped down my code as much as possible to paste into here:
The HTML input:
<form action="deletesearchresults.php" method="GET">
<p><b>First Part Of Postcode</b>
<input type="text" name="searchpostcode"></b> </p>
<p><b>Category</b>
<input type="text" name="searchfaroukcat"></b>
<input type="submit" value="Search">
</p>
</form>
The PHP results display:
<?php
mysql_connect("myip", "my_username", "my_password") or die("Error connecting to database: ".mysql_error());
mysql_select_db("my_db") or die(mysql_error());
$sql = mysql_query("SELECT * FROM
GoogleBusinessData
INNER JOIN TblPostcodeInfo ON GoogleBusinessData.BusPostalCode = TblPostcodeInfo.PostcodeFull WHERE PostcodeFirstPart = '$_GET[searchpostcode]' and FaroukCat = '$_GET[searchfaroukcat]' LIMIT 0,20");
while($ser = mysql_fetch_array($sql)) {
echo "<p>" . $ser['BusName'] . "</p>";
echo "<p>" . $ser['PostcodePostalTown'] . "</p>";
echo "<p>" . $ser['PostcodeArea'] . "</p>";
echo "<p>" . $ser['FaroukCat'] . "</p>";
echo "<p> --- </p>";
}
?>
This works great until I leave one field blank, in which case it returns no results as it thinks I am asking for results where that field is empty or null, which I don't wat. I want all of the results where that form field is empty.
I tried combining a like % [myfeild] % etc but I only want the results to display exactly what is on the field and not just the ones that contain what is in the field, for example searching for the postcode "TR1" would return results for TR1, TR10, TR11 etc.
I believe I may need an array but after 3 days of trying, I just don't know how to get this done.
Any help would be amazing.
edit: Also, I will be adding up to ten fields to this form eventually and not just the two in this example so please bear this in mind with any suggestions you may have.
try using isset()
example
if(isset($_GET[searchpostcode]) && isset($_GET[searchfaroukcat])){
$fields = "WHERE PostcodeFirstPart = '$_GET[searchpostcode]' and FaroukCat = '$_GET[searchfaroukcat]'";
}elseif(isset($_GET[searchpostcode]) && !isset($_GET[searchfaroukcat])){
$fields = "WHERE PostcodeFirstPart = '$_GET[searchpostcode]'";
}elseif(!isset($_GET[searchpostcode]) && isset($_GET[searchfaroukcat])){
$fields = "WHERE FaroukCat = '$_GET[searchfaroukcat]'";
}else{
$fields = "";
}
$sql = "SELECT * FROM
GoogleBusinessData $fields
INNER JOIN TblPostcodeInfo ON GoogleBusinessData.BusPostalCode = TblPostcodeInfo.PostcodeFull LIMIT 0,20";
You do however need to escape your $_GET variables however i would highly recommend using PDO/mysqli prepared statements http://php.net/manual/en/book.pdo.php or http://php.net/manual/en/book.mysqli.php
or try a foreach loop
foreach($_GET as $keys=>$value){
$values .= $keys."='".$value."' and";
}
$values = rtrim($values, " and");
if(trim($values) != "" || trim($values) != NULL){
$query = "WHERE ".$values;
}else{
$values = "";
}
$sql = "SELECT * FROM `test`".$values;