Live search engine logic behind query - php

I have problems creating a multiple field live search engine using AJAX and PHP.
Up to now there was no need to search for multiple fields, so I had a simple query that worked fine for only one field.
Because of a live search using onkeyup function I recognized some problems. The first problem i need to explain:
The structure of the table is quite simple: zipcode | city
For example, someone enters 12345; of course this would be the zipcode. But what in case if someone enters 12345 hometown so the first keyword would be the zipcode, second the city?
The keywords will be split by using preg_split('/[\s]+/', $search_term) so as a result I receive an array with the single keywords that will be searched for. in the case above it would be: key[0] => 12345 and key[1] => hometown.
The query I use is like:
$where = "";
$search_term = preg_split('/[\s]+/', $search_term); //splits the whole string into single keywords
$total_search_terms = count($search_term); //counts the array-keys from $search_term
foreach ($search_term as $key=>$single_term) {
$where .= "`zipcode` LIKE '$single_term%' OR `city` LIKE '$single_term%' ";
if ($key != ($total_search_terms - 1)){ //adds AND to the query in case in case of a non empty array-key
$where .= " AND ";
}
}
$query = $db->query("SELECT COUNT(*) FROM table WHERE $where");
...
Okay, so far so good. Now the problem is that the keywords can match each field again and again.
To give further example:
In case from above entering 12345 hometown it means that key[0] => 12345 can match field zipcode OR city. This condition is egual to key[1] => hometown, even this can match field zipcode OR city. So ,even when entering other way round: hometown 12345 means the same.
And this is the first problem I have.
I'm looking for a logic to structure the query. So in case of entering 12345 hometown I would like to have something like that:
When key[0] => 12345 matches field zipcode dont check key[1] => hometown if that matches in zipcode OR city because key[0] matches already in zipcode so it´s quite logical that key[1] needs to be city.
UPDATE
Okay, to tell my second problem I would like you to have a look at the answer from david strachan
He mentioned that a problem will be caused when the city contains more than one string. Let's say the search string would be something like:
12345 New York
The keys would be:
key[0] => 12345, key[1] => New, key[2] => York
Okay, now the problem is that I could check if one of the keys contains integers or not and in case of a string-length of exactly 5 I know that it will be the zipcode.
key[0] => 12345 //if ( stringlen(key[0|) === 5) === true && is_int(key[0]) === true) {zipcode}
So far so good but the real problem is the logic behind the strings of the cities. My first thoughts were that I could say that all keys that do not contain integers must be the city so I could convert them into one key.
key[1] => New, key[2] => York //if ( !is_int(key[1|) === true && !is_int(key[2|) === true) {$create_one_key = array_fill_keys(key[1], key[1]+key[2]);}
Alright, but what in case I would like to add street names in the future? I do not know how to separate and test for street name and even for the city name.

Another approach is to use JQuery Autocomplete to search MySQL database. The following code uses PDO.
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css" />
<script type="text/javascript">
jQuery(document).ready(function(){
$('#zipsearch').autocomplete({source:'suggest.php', minLength:2});
});
</script>
<style type="text/css">
li.ui-menu-item { font-size:10px}
</style>
</head>
<body>
<h2>jQuery UI Autocomplete - With MySQL </h2>
<form onsubmit="return false;">
Search:
<input id="zipsearch" type="text" size ="60"/>
</form>
suggest.php
require("dbinfo.php");//db connection strings
// if the 'term' variable is not sent with the request, exit
if ( !isset($_REQUEST['term']) )
exit;
$term = $_REQUEST['term'];
if (is_numeric($term)){
$query = "SELECT * from ziptest WHERE zip LIKE ? OR address LIKE ? LIMIT 0,10";
}else{
$query = "SELECT * from ziptest WHERE city LIKE ? OR state LIKE ? LIMIT 0,10";
}
$term.="%";
// connect to the database
try {
$dbh = new PDO("mysql:host=$host;dbname=$database", $username, $password);
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
// Prepare statement
$stmt = $dbh->prepare($query);
// Assign parameters
$stmt->bindParam(1,$term);
$stmt->bindParam(2,$term);
// setting the fetch mode
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$stmt->execute();
$data = array();
while($row = $stmt->fetch()) {
$data[] = array(
'label' => $row['address'] .', '. $row['city'] .', '. $row['state'] .', '.$row['zip'] ,
'value' => "ID ".$row['id'] .': '.$row['address'] .', '. $row['city'] .', '. $row['state'] .', '.$row['zip']
);
}
echo json_encode($data);
}
catch(PDOException $e) {
echo "I'm sorry I'm afraid you can't do that.". $e->getMessage() ;// Remove or modify after testing
file_put_contents('PDOErrors.txt',date('[Y-m-d H:i:s]'). $e->getMessage()."\r\n", FILE_APPEND);
}
// close the connection
$dbh = null;
DEMO

Check to see if $search_term[0] is string(city) or int(zipcode) by addition of 0 Then format query accordingly.
$search_term = '1234 paisley';
$search_term = preg_split('/[\s]+/', $search_term); //splits the whole string into single keywords
$total_search_terms = count($search_term); //counts the array-keys from $search_term
$test = $search_term[0]+0;//If string returns 0
if($total_search_terms == 1){
if ($test == 0 ){
$where = "WHERE `city` LIKE `%$search_term[0]%`";
}else{
$where = "WHERE `zipcode` LIKE `%$search_term[0]%` ";
}
}else{
if ($test == 0 ){
$where = "WHERE `zipcode` LIKE `%$search_term[1]%` AND `city` LIKE `%$search_term[0]%`";
}else{
$where = "WHERE `zipcode` LIKE `%$search_term[0]%` AND `city` LIKE `%$search_term[1]%`";
}
}
$query = "SELECT COUNT(*) FROM table $where";
echo $query;
One problem will be how you treat New York. I will leave you how to work this out.
EDIT
New York $total_search_terms > 2

Related

How to search multiple words?

I was trying to make a search engine so far I had done with it and the feature I lack in it was, when user queries a long sentence or two or three words with on not in line-wise in my DB is not going to show and it shows 0 results.
So far it is working fine with the one-word search it is doing a great job with that.
public function getResultsHtml($page, $pageSize, $term){
$fromLimit = ($page - 1) * $pageSize;
//page 1: (1-1) * 20
//page 2:(2-1) * 20
$query = $this->con->prepare("SELECT *
FROM sites WHERE title LIKE :term
OR url LIKE :term
OR keywords LIKE :term
OR description LIKE :term
ORDER BY clicks DESC
LIMIT :fromLimit,:pageSize");
$searchTerm = "%" . $term ."%";
$query->bindParam(":term",$searchTerm);
$query->bindParam(":fromLimit",$fromLimit,PDO::PARAM_INT);
$query->bindParam(":pageSize",$pageSize,PDO::PARAM_INT);
$query->execute();
$resultsHtml ="<div class='siteResults'>";
while($row = $query->fetch(PDO::FETCH_ASSOC)){
$id = $row["id"];
$url = $row["url"];
$title = $row["title"];
$description = $row["description"];
$title = $this->trimField($title,55);
$description = $this->trimField($description,230);
$resultsHtml .="<div class='resultContainer'>
<h3 class='title'>
<a class='result' href='$url' data-linkId='$id'>
$title
</a>
</h3>
<span class='url'>$url</span>
<span class='description'>$description</span>
</div>";
}
$resultsHtml .= "</div>";
return $resultsHtml;
}
So when user searches apple it is retrieving the data and we can see the search result in "apple store search" in the first image.But in second image when we search "apple search" it should be able to show us the "apple store search".
first image
Second image
First you need to breakdown your $term into separated words. With European languages, you can simply use explode:
<?php
$terms = explode(' ', $term);
// lets say your $term is 'apple orange lemon banana'
// $terms would be ['apple', 'orange', 'lemon', 'banana']
Prepare Terms List for Binding
Then, I'd build a key-value array for the terms binding:
<?php
// build a term list with term key (:term{number}) and associated term
// for binding
$term_params = [];
foreach ($terms as $key => $term) {
$term_params[":term{$key}"] = "%{$term}%";
}
// $term_params would be:
// [
// ':term0' => '%apple%',
// ':term1' => '%orange%',
// ':term2' => '%lemon%',
// ':term3' => '%banana%',
// ]
Prepare the Where Clause in SQL for Binding
Now, supposed the logics is all the terms need to show up in either of the target fields:
<?php
// a list of fields to search from
$fields = ['title', 'url', 'keywords', 'description'];
// build a where clause SQL based on the terms and fields
$or_where_clauses = [];
foreach (array_keys($term_params) as $term_key) {
$or_where_clauses[] = implode(' OR ', array_map(function ($field) use ($term_key) {
return "{$field} LIKE {$term_key}";
}, $fields));
}
$where_clauses_sql = implode(' AND ', array_map(function ($term_clause) {
// quote each term clause with bracket for proper OR logic to work
return '(' . $term_clause . ')';
}, $or_where_clauses);
The resulting where clauses sql would be:
(title like :term0 OR url like :term0 OR keywords like :term0 OR description like :term0)
AND
(title like :term1 OR url like :term1 OR keywords like :term1 OR description like :term1)
AND
...
...
(title like :termN OR url like :termN OR keywords like :termN OR description like :termN)
Putting Everything Together
I can then build the SQL string and bind the terms to the query accordingly:
<?php
// prepare the select statement
$query = $this->con->prepare("SELECT *
FROM sites WHERE {$where_clauses_sql}
ORDER BY clicks DESC
LIMIT :fromLimit,:pageSize");
// bind the terms
foreach ($term_params as $key => $value) {
$query->bindParam($key, $value);
}
$query->bindParam(":fromLimit", $fromLimit, PDO::PARAM_INT);
$query->bindParam(":pageSize", $pageSize, PDO::PARAM_INT);
$query->execute();
// ...
Shortcomings and Potential Solution
Please note that this approach does not understand the number of occurrence of terms in the field. And the way to separate words is far from perfect. For example:
It didn't handle punctuation marks.
It couldn't search for plural terms with the singular, or visa verse.
It could be matching part of a word by mistake (e.g. search "sing" and match "dressing").
It couldn't deal with CJK or languages without space).
You can use software like Elastic Search for better feature. With plugin and proper config, you can give even sort results with relevance, or give different field a different importance in the search process etc.
But that is an entirely different software than SQL server to use. You'd need to learn and plan how to index your contents there as well as just saving your data to SQL.
we dont know how u get search words from user, but as i guess u get them as an array. so you can try below code:
<?php
...
$textSearch = "";
for($i = 0 ; $i< count($userInputs);$i++){
if($i !== count($userInputs) -1){
$userInputData = $userInputs[$i];
$textSearch .= "'%$userInputData%' OR";
}else{
$textSearch .= "'%$userInputData%'";
}
}
and put $textSearch into your query.
remember , $userInputs is an array that u had before.
UPDATE
as your images shown, you can add $userInput = explode(" ",$textFromUser) in very begin of given code.

php foreach loop search mysql table with several words

I have a mysql table called foods with columns "id, name, addinfo, picname, mg1cup, mg100g". I have a form where the user can submit between 1-20 food names. The php file takes the submitted food names in an array called $terms[]. I need to search the sql table for all terms and return results for all columns for each of the terms.
However, the results are only showing the first term submitted, repeated as many times as there are inputs (for example, if two words were inputted, the first term gets outputted in the results twice - instead of first word results, then second word results).
I don't know what I'm doing wrong. Here's my code (I haven't added the function to sanitize the strings yet):
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
//connect to the wordpress (bluehost)DB
require_once '../../../wp-config.php';
$link = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD) or die('Could not connect to mysql');
$Db = mysql_select_db(DB_NAME, $link) or die('Could not select database.');
//check to see if the search term has a value, matches "name" column in DB, and if so, put it into an array called terms
if (isset($_POST['terms'])) {
$terms = ($_POST['terms']);
if (count($terms) > 0 ) {
$results=array();
foreach($terms as $term) {
$sql = 'SELECT * from `wpqr_foods` WHERE `name` like "%'. $term .'%" ORDER BY name ASC';
$Q1 = mysql_query($sql);
if(mysql_num_rows($Q1)) {
while ($Res = mysql_fetch_assoc($Q1)) {
$results[] = $Res;
}
}
//$results = mysql_query($sql);
$sql = 'SELECT * from wpqr_foods WHERE name LIKE "%'. $term .'%" ORDER BY name ASC';
$Q2 = mysql_query($sql);
//get results
if(mysql_num_rows($Q2)) {
while ($Res = mysql_fetch_assoc($Q2)) {
$results[] = $Res;
}
}
}
if (count($results) > 0 ) {
foreach ($results as $CurRes ) {
echo $CurRes['name']. "<br/>";
echo $CurRes['addinfo']. "<hr/>";
/*
[id] => 5
[name] => Apples
[value] => Yes
[addinfo] => They can eat apples. They can also eat the skin of the apple and the leaves of the apple tree, but the tree leaves are high in calcium, so limit their intake. They can also chew on the apple tree branches.
[picname] => apple
[mgc1cup] => 5.8
[mgc100g] => 4.6
*/
}
}
else {
echo "(nothing entered)";//MEANS $TERM IS EMPTY
}
}
else {
echo "(nothing entered)";//means $_POST IS NOT SET (end of if(isset($_POST['term'])) { )
}
}
//function to sanitize array values from form
function sanitizeString($var) {
if (is_array($val))
{
foreach ($val as $k => $v)
{
$val[$k] = htmlentities(strip_tags($v),ENT_QUOTES);
}
}
else
{
$val = htmlentities(strip_tags($terms),ENT_QUOTES);
}
return $val;
}
?>
The HTML is
<div class="my-form">
<form role="form" id="step1" method="post" action="/wp-content/themes/mia/vitcdata.php">
<p class="text-box"><label for="box1">Food <span class="box-number">1 </span></label><input type="text" name="terms[]" value="" placeholder="apples" id="box1" /> <a class="add-box" href="#">Add More</a></p>
<p><input type="submit" value="Submit" /></p>
</form>
The form has dynamic form fields which users can add via javascript, and they can add up to 20 text inputs, in which all inputted terms get added to the $terms[] array.
So, if I test it, use two fields, and input "apples" and "bananas", the results show all the data for "apples" repeated twice.
Check this, you can check a related question here:
Using OR in LIKE Query in MySQL to compare multiple fields
You might have to do something like this in your query.
$sql = 'SELECT * from wpqr_foods WHERE name LIKE "%'. $term .'%" OR addinfo LIKE "%'. $term .'%" ORDER BY name ASC';
OR,
$sql = 'SELECT * FROM `wpqr_foods` WHERE CONCAT(name, addinfo ) LIKE "%'. $term .'%" ORDER BY name ASC';
I would recommend the following two ways forward:
It looks like the code block that queries the database and pushes results into $results is duplicated. You probably want to get rid of the duped block as that will create 2x results for each distinct term.
I suspect what's actually getting passed to the server through the form is a string containing whitespace-separated (or commas, or whichever separator the user chose to enter) terms. Even though you've chosen to pass it (and receive it server-side) as an array, it is actually a string and you will have to explode it (or some other method) yourself into an array. To check if that's the case (and if you haven't do so already), somewhere inside the foreach ($terms as $term) loop you should inspect $term to see if it is what you expect it to be.

Php mysql match (multiple) words in multiple columns with spaces

I am trying to figure out how and what function i need for my query, still not sure on using Like, concat or what part etc.
My situation is as such
1.) I have multiple columns(Country, City, State, Location)
2.) Only 1 search input
3.) Search input can be 1 word, or multiple words also ignore spacing(e.g. "Center City or CenterCity or Center City Philadelphia) etc
And it will return the rows that matches the words from the different columns.
Below is my attempt, but it is not returning anything at the moment. Thanks for your time
Php:
<?php
ini_set('display_errors', 1); error_reporting(E_ALL);
include 'connect.php';
if($_POST)
{
$searchaddress = ($_POST['searchaddress']);
$result=mysqli_query($con,"SELECT *
FROM Listing WHERE CONCAT(country,state,city,Location) LIKE '%$searchaddress%' AND Status='Open'") or die( mysqli_error($con));
$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 );
}
?>
Without knowing your exact data and what $searchaddress is like, it is hard to tell why it fails.
You are talking about ingoring whitespaces, but just pass in a single searchtag - and the expression LIKE '%something something else%' will not ignore whitespaces.
If you want to have the least amount of results with all given words matching, you should put in more effort and use a or/and combination of searchtags / columns. You can do this programmatically.
Assuming, you have 2 keywords entered: Center Detroid, you basically want to generate the searchquery:
FROM Listing WHERE
(
country LIKE '%Center%' OR
state LIKE '%Center%' OR
city LIKE '%Center%' OR
Location LIKE '%Center%'
)
AND
(
country LIKE '%Detroid%' OR
state LIKE '%Detroid%' OR
city LIKE '%Detroid%' OR
Location LIKE '%Detroid%'
)
To achieve that, you need to know two things:
The fieldnames you want to search in.
The keywords.
Then, the following snippet will generate the where part as required:
$search = "Detroid City Center";
$keywords = explode (" ", $search);
$columns = array("country", "state", "city", "location");
$andParts = array();
foreach ($keywords AS $keyword){
$orParts = array();
foreach($columns AS $column){
$orParts[] = $column . " LIKE '%" . mysql_real_escape_string($keyword) . "%'";
}
$andParts[]= "(" . implode($orParts, " OR ") . ")";
}
$and = implode ($andParts, " AND ");
echo $and;
The example given in the array would produce
(
country LIKE '%Center%' OR
state LIKE '%Center%' OR
city LIKE '%Center%' OR
location LIKE '%Center%'
)
AND
(
country LIKE '%City%' OR
state LIKE '%City%' OR
city LIKE '%City%' OR
location LIKE '%City%'
)
AND
(
country LIKE '%Detroid%' OR
state LIKE '%Detroid%' OR
city LIKE '%Detroid%' OR
location LIKE '%Detroid%'
)
This will Match ANY row, where Center, City or Detroid is appearing AT LEAST ONCE in ONE of all (search-)fields per row.
Updated answer for searching each word in the address fields:
$searchaddress = "some address to find";
$address_parts = explode(" ", trim($searchaddress));
$sql_parts = array();
foreach($address_parts as $part) {
$sql_parts[] = 'full_address LIKE "%'.$part.'%"';
}
$query = 'SELECT *, CONCAT(country,state,city,Location) AS full_address FROM Listing WHERE `Status` = "Open" HAVING '.implode(' OR ', $sql_parts);

PHP Search Engine no results are returned even if the input matches data in the table

I'm trying to create a search engine for my website where users can enter keywords and the PHP script will search the 'name' and 'description' columns of my fyp_items table. So far I have managed to break down the input to an array of words and am try to execute a SELECT query on my database.
THE ISSUE is that it fails to find the items even if the keyword matches that of the data in the table. Below is my script...I hope someone can help me.
if(empty($_POST)=== false){
$output = '';
$error = '';
$input = $_POST['search_input'];
$i=0;
if($input){
$keyword = explode(" ", $input);
require ('core/dbconnection.php');
//If a user is logged in check if the user is Admin or Customer.
if(isset($_SESSION['userid'])){
if($admin == 1){
}
}else{
//If user is not logged in search items table only.
$search_items = "SELECT * FROM fyp_items WHERE ";
foreach($keyword as $k){
$k = mysql_real_escape_string($k);
$i++;
if($i == 1){
$search_items .= "name LIKE '$k' OR description LIKE '$k'";
}else
$search_items .= " OR name LIKE '$k' OR description LIKE '$k'";
}
$item_qry = mysql_query("$search_items")or die(mysql_error());
$numrows = mysql_num_rows($item_qry);
if($numrows > 0){
$output = 'found it';
}else
$error = '<p class="pageerror">Sorry, what you were looking for was not found.</p>';
}
}else
$error = '<p class="pageerror">Please enter your search terms.</p>';
I have tested the post by echoing the output and I have also echoed the $search_items variable to get this...
http://awesomescreenshot.com/05c2fwytac
Your help will be much appreciated!
You're building an incorrect query string, that'll be something like
SELECT ... WHERE name LIKE 'foo' OR description LIKE 'foo'
a LIKE comparison without wilcards is pointless. You've functionally got the equivalent of
SELECT ... WHERE name='foo' OR description='foo'
The wildcards allow substring matching in the fields:
SELECT ... WHERE name='%foo%' OR description = '%foo%'
so the word foo can appear ANYWHERE in the field and match. Right now your query will only match if foo is the ONLY thing in either field.
And these sorts of queries are highly inefficient, especially as the number of search terms climbs. You should be suing a fulltext search: https://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

Advance Searching, PHP & MySQL

I'm trying to create an Advanced Searching form that sort of look like this ;
http://img805.imageshack.us/img805/7162/30989114.jpg
but what should I write for the query?
I know how to do it if there is only two text box but three, there's too many probability that user will do.
$query = "SELECT * FROM server WHERE ???";
What should I write for the "???"
I know how to use AND OR in the query but lets say if the user only fill two of the textbox and one empty. If I write something like this ;
$query = "SELECT * FROM server WHERE model='".$model."' and brand='".$brand."' and SN='".$SN.'" ";
The result will return as empty set. I want the user can choose whether to fill one,two or three of the criteria. If I use OR, the result will not be accurate because if Model have two data with the same name (For example :M4000) but different brand (For example : IBM and SUN). If I use OR and the user wants to search M4000 and SUN, it will display both of the M4000. That's why it is not accurate.
If the user can decide how many criteria he wants to enter for your search and you want to combine those criteria (only those actually filled by the user), then you must dynamically create your SQL query to include only those fields in the search that are filled by the user. I'll give you an example.
The code for a simple search form could look like this:
$search_fields = Array(
// field name => label
'model' => 'Model',
'serialNum' => 'Serial Number',
'brand' => 'Brand Name'
);
echo "<form method=\"POST\">";
foreach ($search_fields as $field => $label) {
echo "$label: <input name=\"search[$field]\"><br>";
}
echo "<input type=\"submit\">";
echo "</form>";
And the code for an actual search like this:
if (isset($_POST['search']) && is_array($_POST['search'])) {
// escape against SQL injection
$search = array_filter($_POST['search'], 'mysql_real_escape_string');
// build SQL
$search_parts = array();
foreach ($search as $field => $value) {
if ($value) {
$search_parts[] = "$field LIKE '%$value%'";
}
}
$sql = "SELECT * FROM table WHERE " . implode(' AND ', $search_parts);
// do query here
}
else {
echo "please enter some search criteria!";
}
In the above code we dynamically build the SQL string to do a search ("AND") for only the criteria entered.
Try this code
<?php
$model="";
$brand="";
$serialNum="";
$model=mysql_real_escape_string($_POST['model']);
$brand=mysql_real_escape_string($_POST['brand']);
$serialNum=mysql_real_escape_string($_POST['serialNum']);
$query=" select * from server";
$where_str=" where ";
if($model == "" && $brand == "" && $serialNum == "")
{
rtrim($where_str, " whrere ");
}
else
{
if($model != "")
{
$where_str.= " model like '%$model%' AND ";
}
if($brand != "")
{
$where_str.= " brand like '%$brand%' AND ";
}
if($serialNum != "")
{
$where_str.= " serialNum like '%$serialNum%' AND ";
}
rtrim($where_str, " AND ");
}
$query.= $where_str;
$records=mysql_query($query);
?>
For those framiliar with mysql, it offers the ability to search by regular expressions (posix style). I needed an advanced way of searching in php, and my backend was mysql, so this was the logical choice. Problem is, how do I build a whole mysql query based on the input? Here's the type of queries I wanted to be able to process:
exact word matches
sub-string matches (I was doing this with like "%WORD%")
exclude via sub-string match
exclude via exact word match
A simple regexp query looks like:
select * from TABLE where ROW regexp '[[:<:]]bla[[:>:]]' and ROW
regexp 'foo';
This will look for an exact match of the string "bla", meaning not as a sub-string, and then match the sub-string "foo" somewhere.
So first off, items 1 and 4 are exact word matches and I want to be able to do this by surrounding the word with quotes. Let's set our necessary variables and then do a match on quotes:
$newq = $query; # $query is the raw query string
$qlevel = 0;
$curquery = "select * from TABLE where "; # the beginning of the query
$doneg = 0;
preg_match_all("/\"([^\"]*)\"/i", $query, $m);
$c = count($m[0]);
for ($i = 0; $i < $c; $i++) {
$temp = $m[1][$i]; # $temp is whats inside the quotes
Then I want to be able to exclude words, and the user should be able to do this by starting the word with a dash (-), and for exact word matches this has to be inside the quotes. The second match is to get rid of the - in front of the query.
if (ereg("^-", $temp)) {
$pc = preg_match("/-([^-]*)/i", $m[1][$i], $dm);
if ($pc) {
$temp = $dm[1];
}
$doneg++;
}
Now we will set $temp to the posix compliant exact match, then build this part of the mysql query.
$temp = "[[:<:]]".$temp."[[:>:]]";
if ($qlevel) $curquery .= "and "; # are we nested?
$curquery .= "ROW "; # the mysql row we are searching in
if ($doneg) $curquery .= "not "; # if dash in front, do not
$curquery .= "regexp ".quote_smart($temp)." ";
$qlevel++;
$doneg = 0;
$newq = ereg_replace($m[0][$i], "", $newq);
}
The variable $newq has the rest of the search string, minus everything in quotes, so whatever remains are sub-string search items falling under 2 and 3. Now we can go through what is left and basically do the same thing as above.
$s = preg_split("/\s+/", $newq, -1, PREG_SPLIT_NO_EMPTY); #whitespaces
for ($i = 0; $i < count($s); $i++) {
if (ereg("^-", $s[$i])) { # exclude
sscanf($s[$i], "-%s", $temp); # this is poor
$s[$i] = $temp;
$doneg++;
}
if ($qlevel) $curquery .= "and ";
$curquery .= "ROW "; # the mysql row we are searching in
if ($doneg) $curquery .= "not ";
$curquery .= "regexp ".quote_smart($s[$i])." ";
$qlevel++;
$doneg = 0;
}
# use $curquery here in database
The variable $curquery now contains our built mysql query. You will notice the use of quote_smart in here, this is a mysql best practice from php.net. It's the only mention of security anywhere in this code. You will need to run your own checking against the input to make sure there are no bad characters, mine only allows alpha-numerics and a few others. DO NOT use this code as is without first fixing that.
You have to provide $model, $brand, $serial which come from your search-form.
$query = "SELECT * FROM `TABLE` WHERE `model` LIKE '%$model%' AND `brand` LIKE '%$brand%' AND `serial` LIKE '%$serial%'";
Also take a look at the mysql doc
http://dev.mysql.com/doc/refman/5.1/en/string-comparison-functions.html
A basic search would work like this:
"SELECT * FROM server WHERE column_name1 LIKE '%keyword1%' AND column_name2 LIKE '%keyword2%' .....";
This would be case for matching all parameters.For matching any one of the criteria, change ANDs to ORs

Categories