Autocomplete search by First Name and Last Name - php

I have created an autosuggestion search box using PHP and jQuery. The user is prompted to insert First name and Last name to find someone that exists in my database, in a table called customers. Table customers holds 2 columns, first_name and last_name.
My search works fine when you type the First name but after pressing space to move and type Last Name does not give any results. The whole problem seems to appear when pressing space button. Any idea how to fix it?
$(document).ready(function($){
$("#customers").autocomplete({
source: "fetch_customers.php?cc=<?php echo $agencyid; ?>",
minLength: 2,
select: function(event, ui) {
var code = ui.item.id;
if (code != '#') {
location.href = '/view-customer/' + code;
}
},
open: function(event, ui) {
$(".ui-autocomplete").css("z-index", 1000);
}
});
});
<?php
$countrycode1 = $_GET['cc'];
$term = trim(strip_tags($_GET['term']));
$term = preg_replace('/\s+/', ' ', $term);
$a_json = array();
$a_json_row = array();
$a_json_invalid = array(array("id" => "#", "value" => $term, "label" => "Only letters and digits are permitted..."));
$json_invalid = json_encode($a_json_invalid);
if ($data = $conn->query("SELECT id, first_name, last_name FROM customers WHERE agency_id='$countrycode1' AND (first_name LIKE '%$term%' OR last_name LIKE '%$term%') ORDER BY first_name , last_name"))
{
while($row = mysqli_fetch_array($data))
{
$firstname = htmlentities(stripslashes($row['first_name']));
$lastname = htmlentities(stripslashes($row['last_name']));
$code = htmlentities(stripslashes($row['id']));
$a_json_row["id"] = $code;
$a_json_row["value"] = $firstname.' '.$lastname;
$a_json_row["label"] = $firstname.' '.$lastname;
array_push($a_json, $a_json_row);
}
}
/* jQuery wants JSON data */
$json = json_encode($a_json);
print $json;
flush();
$conn->close();

Split Your $term like this.
$splited_term = explode(" ",$term);
$first_term = $splited_term[0];
$last_term = (isset($splited_term[1]) && !empty($splited_term)) ? $splited_term[1] : null;
Generate your query according
$query = "SELECT id, first_name, last_name FROM customers WHERE agency_id='$countrycode1' AND ";
if(!empty($first_term)){
$query.= "(first_name LIKE '%$first_term%' OR last_name LIKE '%$first_term%'" ;
}
if(!empty($last_term)){
$query .= ((!empty($first_term)) ? " OR " : " ( " )." first_name LIKE '%$last_term%' OR last_name LIKE '%$last_term%')" ;
}
$query .= ((empty($last_term)) ? ")" : "")." ORDER BY first_name , last_name";
This will support
"Milind Patel"
"Patel Milind"
" Milind"
" Patel"
"Milind"
"Patel"
So Your code should be like this.
<?php
$countrycode1 = $_GET['cc'];
$term = trim(strip_tags($_GET['term']));
$term = preg_replace('/\s+/', ' ', $term);
$splited_term = explode(" ",$term);
$first_term = $splited_term[0];
$last_term = (isset($splited_term[1]) && !empty($splited_term)) ? $splited_term[1] : null;
$a_json = array();
$a_json_row = array();
$a_json_invalid = array(array("id" => "#", "value" => $term, "label" => "Only letters and digits are permitted..."));
$json_invalid = json_encode($a_json_invalid);
$query = "SELECT id, first_name, last_name FROM customers WHERE agency_id='$countrycode1' AND ";
if(!empty($first_term)){
$query.= "(first_name LIKE '%$first_term%' OR last_name LIKE '%$first_term%'" ;
}
if(!empty($last_term)){
$query .= ((!empty($first_term)) ? " OR " : " ( " )." first_name LIKE '%$last_term%' OR last_name LIKE '%$last_term%')" ;
}
$query .= ((empty($last_term)) ? ")" : "")." ORDER BY first_name , last_name";
if ($data = $conn->query($query))
{
while($row = mysqli_fetch_array($data))
{
$firstname = htmlentities(stripslashes($row['first_name']));
$lastname = htmlentities(stripslashes($row['last_name']));
$code = htmlentities(stripslashes($row['id']));
$a_json_row["id"] = $code;
$a_json_row["value"] = $firstname.' '.$lastname;
$a_json_row["label"] = $firstname.' '.$lastname;
array_push($a_json, $a_json_row);
}
}
/* jQuery wants JSON data */
$json = json_encode($a_json);
print $json;
flush();
$conn->close();

Related

PHP parameterized on mysql query with LIKE and CONCAT on partial string

I'm struggling with this query. I'm trying to match one of two fields against a partial string for an ajax call. Start typing a name, it should match against first or last name.
My parameterized query is returning 0 rows on LIKE statement.
I've tried answers from here and here and here.
I'm afraid I'm missing something simple, but I can only think that the parameters aren't passing in right for the partial string.
<?
$access = 3;
$dbConnect = true;
require "../scripts/php/scriptSecurity.php";
// Partial name given by user.
$name = $_GET["name"];
if (!empty($name)){
if (strpos($name, " ")){
$nameParts = explode(" ", $name);
if (strpos($nameParts[0], ",")) {
$last = str_replace(",", "",$nameParts[0]);
$first = $nameParts[1];
}
else {
$first = $nameParts[0];
$last = $nameParts[1];
}
}
else {
$last = str_replace(",", "", $name);
$first = str_replace(",", "", $name);
}
// Freak out that maybe some hidden character is in the name.
$last = preg_replace( "/[^a-zA-Z0-9']/", "", $last );
$first = preg_replace( "/[^a-zA-Z0-9']/", "", $first );
if ($last != $first){
$query = "SELECT * FROM students WHERE LastName LIKE CONCAT('%', ? , '%') AND FirstName LIKE CONCAT('%', ? , '%') ORDER BY LastName, FirstName LIMIT 30" ;
}
else {
$query = "SELECT * FROM students WHERE LastName LIKE CONCAT('%', ? , '%') OR FirstName LIKE CONCAT('%', ? , '%') ORDER BY LastName, FirstName LIMIT 30";
}
if ($nameStmt = $connect->prepare($query)){
$nameStmt->bind_param('ss', $last, $first);
if (!$nameStmt->execute()) {
echo $nameStmt->error;
}
$result = $nameStmt->get_result();
$count = 0;
if (empty($result)){
while ($row = $result->fetch_assoc()){
$count++ ;
if ($count % 2 != 0)
$class="odd";
else
$class="even";
?>
<div class="studentRow <?php echo $class ?>"><?php echo $row["LastName"] . ", " . $row["FirstName"] . " " . $row["MiddleName"] ?> <div><a class="stuPass" id="stuPass_<?php echo $row["id"] ?>" href="scripts/getPass.php?id=<?php echo $row["id"] ?>">Pass</a></div><div><a class="stuDetails" id="stuDetails_ <?php $row["id"] ?>" href="scripts/students/getDetails.php?id=<?php echo $row["id"] ?>">Details</a></div></div>
<div class="stuDetails hidden" id="stuDetailsHolder_<?php echo $row["id"]?>"></div>
<?php
}
}
else {
echo "Results are empty.";
}
}
else {
echo "<br />". $connect->error;
}
}
Here is the code from uploading the data in the db. I was worried that I might have hidden characters lurking, but I think I have them all stripped out.
$fStu = new SplFileObject('../resources/students.txt');
$fStu->seek($count);
list($year,$building,$id,$last,$middle,$first,$gender,$grade,$gradYear) = explode(",",$fStu->current());
if (!empty($year)){
$stuQuery = "INSERT INTO students (LastName, MiddleName, FirstName, StudentId, Gender, Grade, GradYear) VALUES (?,?,?,?,?,?,?)";
$stuStmt = $connect->prepare($stuQuery);
$last = preg_replace( "/[^a-zA-Z0-9']/", "", $last );
$first = preg_replace( "/[^a-zA-Z0-9']/", "", $first );
$middle = preg_replace( "/[^a-zA-Z0-9']/", "", $middle );
$gender = preg_replace( "/\r|\n|\s+/", "", $gender );
$id = intval(preg_replace('/\D/', '', $id));
$gradYear = intval(preg_replace('/\D/','', $gradYear));
$grade = intval(preg_replace('/\D/','', $grade));
$stuStmt->bind_param("sssisss", $last, $middle, $first,$id,$gender,$grade,$gradYear);
$stuStmt->execute();
echo $count . "||" . $last . ", " . $first . " (" . $id . ")";
}
else {
$count = -1;
echo $count . "||Complete.";
}
Here's the main page passing the partial name with the querystring.
$(document).ready(function(){
$("#name").on("change paste keyup", function(e){
e.preventDefault();
$.ajax({url: "process/students.php?name=" + $("#name").val(),
success: function(result){
$("#results").removeClass("hidden");
$("#results").html(result);
}
});
});
Here's a set of data getting uploaded.
> > Current School Year,Current Building,Student Id,Student Last Name,Student Middle Name,Student First Name,Student Gender,Student
> > Grade,Grad Year 2018,111,11111111111,Doe,Jane,,F,09,2021
> > 2018,111,22222222222,Doe,John,,M,09,2021
This is tagged as PDO. If you really are using PDO and not mysqli then you cannot bind multiple parameters in a single statement as you are trying to. They should be declared individually and if you are using ? as placeholders they need to be numbered.
If you are using LIKE you must add the % signs to either side of the variable which you are going to bind, you cannot include them in your query as you are trying to.
As far as your query method, instead of trying to split your user input into first and last names why not concat the name fields from the database and search against the result of that instead?
SELECT * FROM students WHERE CONCAT_WS(' ', FirstName, LastName) LIKE '%whatever%';

PHP Parameterized mysql statement with LIKE clause returns command out of sync

I am trying to use a LIKE clause with a parameterized query with php and mysql. Every time I try though, I'm getting different errors.
I've tried to implement solutions from here, here, and here. Each of these is throwing different errors, so I'm afraid the problem is in something that I'm missing. If I try with an array in the execute function, I get Command out of sync error. When I try binding values or parameters, I'm getting a can't bind on string error.
I'm at a loss for what I'm missing.
Thanks for any help!
<?
$access = 3;
$dbConnect = true;
require "../scripts/php/scriptSecurity.php";
// Partial name given by user.
$namePart = $_GET["namePart"];
// Deal with name parts. last, first middle or first middle last, or first last
if (strpos($namePart, ',') !== false){
$arr_name = explode(",", $namePart);
$lName = $arr_name[0];
if (strpos($arr_name[1], " ") !== false){
$firstName = substr($arr_name[1], 0, strpos($arr_name[1], " ", 1));
$middleName = substr($arr_name[1], strpos($arr_name[1], " ", 1));
}
}
elseif (strpos($namePart, " ") !== false){
$arr_name = explode(" ", $namePart);
if (sizeOf($arr_name) == 3) {
$fName = $arr_name[0];
$lName = $arr_name[3];
$mName = $arr_name[2];
}
elseif (sizeOf(arr_name) == 2) {
$fName = $arr_name[0];
$lName = $arr_name[1];
$mName = $arr_name[1];
}
else {
$fName = $namePart;
$mName = $namePart;
$lName = $namePart;
}
}
else {
$fName = $namePart;
$lName = $namePart;
$mName = $namePart;
}
// Get rid of extra spaces.
$fName = str_replace(" ", "", $fName);
$lName = str_replace(" ", "", $lName);
$mName = str_replace(" ", "", $mName);
// build query
$query = "SELECT LastName, FirstName, MiddleName, StudentId, Gender, Grade, GradYear FROM students WHERE LastName LIKE ? OR FirstName LIKE ? OR MiddleName LIKE ? ORDER BY LastName, FirstName LIMIT 20";
$stmt = $connect->prepare($query);
// execute
$stmt->execute(array('%'.$lName.'%', '%'.$fName.'%', '%'.$mName.'%'));
$result = $stmt->get_result();
// post results
if (!$result) {
echo $connect->error;
echo "No Results";
}
else {
echo "Results";
while ($row = $result->fetch_assoc()){
?>
<div><? echo $row["LastName"] . ", " . $row["FirstName"] . "(" . $row["StudentId"] . ")"?> </div>
<?php
}
}
?>
You pass the string in param with wildchar in wrong way you can use a simplest way managing the wildchar with concat and assign the pure var as param
$query = "SELECT LastName, FirstName, MiddleName, StudentId, Gender, Grade, GradYear
FROM students
WHERE LastName LIKE concat('%',?, '%')
OR FirstName LIKE concat('%',?, '%')
OR MiddleName LIKE concat('%',?, '%')
ORDER BY LastName, FirstName
LIMIT 20";
$stmt = $connect->prepare($query);
// execute
$stmt->execute(array($lName, $fName, $mName));

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

Php search query with range filter

I am trying to do a search query, but not sure how to put everything together. I am having problem with the range filter part.
What i am trying to achieve:
A search form that
1.) If field A,B(not empty) then put in the search query
2.) search through price column with (price lower range, price higher range)
include the results if it matches Field A,B(if it is not empty) and price(if it is in range).
(if search Fields A, B are empty then display all results that exist between range).
Thanks for your time.
The codes that i have now.
<?php
ini_set('display_errors', 1); error_reporting(E_ALL);
session_start();
include 'connect.php';
if($_POST)
{
$A = ($_POST['A']);
$B = ($_POST['B']);
$C = ($_POST['C']);
$pricelow = ($_POST['pricelow']);
$pricehigh = ($_POST['pricehigh']);
$sql = array();
if (!empty($A)) {
$sql[] = "A='$A'";
}
if (!empty($B)) {
$sql[] = "B='$B'";
}
if (!empty($C)) {
$sql[] = "C='$C'";
}
if (!empty($price)) {
for($i = pricelow; $i<pricehigh; $i++){
$price = $i;
}
$sql[] = "price='$price'";
$sql = implode(' AND ', $sql);
$sql = "SELECT * FROM Listing" . (!empty($sql)? " WHERE " . $sql: '');
$result = mysqli_query($con,$sql);
$output = array();
// fetch your results
while( $row = mysqli_fetch_assoc($result) )
{
// add result row to your output's next index
$output[] = $row;
}
// echo the json encoded object
echo json_encode( $output );
}
?>
Edit:
$sql = "SELECT * FROM Listing" . (!empty($sql)? " WHERE " . $sql: '') . ("AND" 'price' BETWEEN "$pricelow" AND "$pricehigh");
Edit:
if (!empty($pricelow) || !empty($pricehigh)) {
$sql[] = $pricehigh>= 'price' and 'price'>=$pricelow ;
}
$sql = array();
$sql = implode(' AND ', $sql);
$sql = "SELECT * FROM Listing" . (!empty($sql)? " WHERE " . implode(" AND ", $sql): '');
<?php
ini_set('display_errors', 1); error_reporting(E_ALL);
session_start();
include 'connect.php';
if($_POST)
{
$A = ($_POST['A']);
$B = ($_POST['B']);
$C = ($_POST['C']);
$pricelow = ($_POST['pricelow']);
$pricehigh = ($_POST['pricehigh']);
$query = "SELECT * FROM Listing WHERE ";
$flag = 0;
if (!empty($A)) {
$query .= $flag==0?" A='$A' ":" AND A = '$A'";
$flag = 1;
}
if (!empty($B)) {
$query .= $flag==0?" B = '$B' ":" AND B = '$B'";
$flag = 1;
}
if (!empty($C)) {
$query .= $flag==0?" C='$C' ":" AND C= '$C'";
$flag = 1;
}
if ($flag == 0) {
$query .= " price > $pricelow AND price > $pricehigh"
}
$result = mysqli_query($con,$query);
$output = array();
// fetch your results
while( $row = mysqli_fetch_assoc($result) )
{
// add result row to your output's next index
$output[] = $row;
}
//your rest of the code
>?
I can't test it so, try and report the result!
You are creating an array of conditions and later you try to use that array as a string. This will not work, as the generated query is invalid. Take a look here, implode is a function which implodes an array using a separator. If you use " AND " as separator, then you will get the string you have desired. So, instead of:
$sql = "SELECT * FROM Listing" . (!empty($sql)? " WHERE " . $sql: '');
do the following:
$sql = "SELECT * FROM Listing" . (!empty($sql)? " WHERE " . implode(" AND ", $sql): '');
and your problem should be solved.
EDIT:
I have read your edit and I mean this code in particular:
if (!empty($pricelow) || !empty($pricehigh)) {
$sql[] = $pricehigh>= 'price' and 'price'>=$pricelow ;
}
$sql = array();
$sql = implode(' AND ', $sql);
$sql = "SELECT * FROM Listing" . (!empty($sql)? " WHERE " . implode(" AND ", $sql): '');
After you build your array you are initializing it again, thus you lose all information you have processed earlier. Then you implode it twice, which is not needed. Try this way:
if (!empty($pricelow) || !empty($pricehigh)) {
$sql[] = $pricehigh>= 'price' and 'price'>=$pricelow ;
}
$sql = "SELECT * FROM Listing" . (!empty($sql)? " WHERE " . implode(" AND ", $sql): '');

Simplifying mysql filter query

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.

Categories