I've created an ajax search box using the keyup function to find profiles in my database.
$('#asearch').keyup(function(){
var search_term = $(this).val();
The problem I'm having is that in my search box once I hit the space bar after typing the first name my page is no longer populated with results. Looking to make it so I can search a first name enter a space and a last name and still have results.
if (isset($_POST['search_term'])){
$search_term = mysql_real_escape_string(htmlentities($_POST['search_term']));
if (!empty($search_term)){
$search = mysql_query("SELECT `firstname`, `lastname` FROM `tempusers`
WHERE `firstname` LIKE '%$search_term%'");
$result_count = mysql_num_rows($search);
while ($results_row = mysql_fetch_assoc($search)) {
echo '<li>', $results_row['firstname'],' ', $results_row['lastname'], '</li></br>';
}
}
}
Tried using a regex $search_term = preg_split('/[\s]+/', $search_term); but it did not work like I was hoping it would. Any tips one may have will be greatly appreciated
Use the trim() function:
Strip whitespace (or other characters) from the beginning and end of a
string.
Plugging it into your code:
$search_term = mysql_real_escape_string(htmlentities(trim($_POST['search_term'])));
By the way, is there a reason that you are using htmlentities on input?
Like Blam said before sometimes is needed to split search string.
I am often using this kind of approach:
$search_term = str_replace(' ','%', trim($search_term));
//"paul dyk" will be changed to "paul%dyk"
//% will match any charackers between those you need. So if you need filter out those names like "pauladyk juk" use $search_term = str_replace(' ',' % ', trim($search_term)); as then spaces must exist, but there can be any words between them.
$search = mysql_query("SELECT CONCAT_WS(' ',firstname, lastname) as full_name FROM tempusers WHERE CONCAT_WS(' ',firstname, lastname) LIKE '%".mysql_real_escape_string($search_term)."%'");
//I would use concat_ws to join strings so if one of them is NULL it will not matter. Using concate with NULL you get no result
while ($results_row = mysql_fetch_assoc($search)) {
echo '< li>' . $results_row['full_name']. '</ li>< br>';
}
Let's start with a "side comment":
You are just looking into the firstname column in your select query. One way to find "firstname lastname" might be to modify your search:
$search = mysql_query("SELECT firstname, lastname FROM tempusers
WHERE CONCAT(firstname, ' ', lastname) LIKE '%$search_term%'");
So if you want to find anything in the lastname you need to look there, too.
Then back to the search query:
What I usually do first is split the query into "tokens". I do that to make sure that I can also find - for example "lastname firstname" and similar queries (for example people might enter "paul dyk" and still want to find "paul van dyk").
A simple way of doing so is by using explode(' ', $search_term), which will work as long as your users behave. Another option would be the regex you mentioned in your question.
Then use these "subqueries" to search your database.
explode() will give you an array of words.
array(
'paul',
'van',
'dyk'
)
From there you need to build your SQL query:
// DON'T DO THE ESCAPE THING BEFORE THIS!
$words = explode(' ', $search_term)
$sql = 'SELECT `firstname`, `lastname` FROM `tempusers` WHERE 1 = 1';
for ($words as $word) {
if (!empty($word)) {
$word = mysql_real_escape_string($word);
$sql .= " AND (firstname LIKE '%" . $word . "%' OR lastname LIKE '%" . $word . "%')";
}
}
$search = mysql_query($sql);
That will build a query where it will search for each word "one by one" and not in a specific order. It's a bit slower, though.
$('#asearch').keyup(function(){
var search_term = this.value.trim();
});
or if insisiting on jQuery
$('#asearch').keyup(function(){
var search_term = $.trim($(this).val());
});
will trim away whitespace at the end/beginning before the value is sent serverside.
Related
I would like to ask about an issue i'm facing.
I have the full name in 1 column stored, example: "John Doe".
But on perform a search for example:
SELECT * FROM client WHERE name LIKE '%Doe John%';
Result: 0 Rows.
If i switch to the exact match store in database it found a row.
SELECT * FROM client WHERE name LIKE '%John Doe%';
Result: 1 Row.
My question is, how to do to search in database without taking the order of word.
In OOP framework the code is:
$like = 'Doe John';
$this->db->select('*')->from('client')->like('name', $like)->get();
Also i tested this but i got the same result:
$this->db->select('*')->from('client');
if($this->containTwoWords($like)) {
$explode = explode(' ', $like);
foreach($explode as $exploded){
$this->db->like('name', $exploded);
}
} else {
$this->db->like('name', $like);
}
$this->db->get();
function containTwoWords($like){
if(strpos($like, ' ') !== false) {
return true;
}
return false;
}
If somebody passed trough this and has better solution i appreciate the sharing !.
One option for your example case would be to check for the first and last names separately:
SELECT * FROM client WHERE name LIKE '%Doe%' AND name LIKE '%John%'
If you have exhausted such tricks with the LIKE operator, then you can look into using MySQL's full text search capabilities.
Try something like this:
<?php
$search_term = 'john doe abc';
$keywords = explode(" ", preg_replace("/\s+/", " ", $search_term));
foreach($keywords as $keyword){
$wherelike[] = " name LIKE '%$keyword%' ";
}
$where = implode(" and ", $wherelike);
$query = "select * from client where $where";
echo $query;
//select * from client where name LIKE '%john%' and name LIKE '%doe%' and name LIKE '%abc%'
?>
Try this name like '%John%' and name like '%Doe%'
If you are wanting to explode the $like variable into first/last name (and you always expect 2 names, separated by a space), then this should work for you.
PHP has the built-in explode() method which does exactly what you are asking.
$like = "John Doe";
$name = explode(" ", $like);
// This created a 0-based array, meaning the first item as split
// by the space between John and Doe is given the array index of 0.
// $name[0] = John
// $name[1] = Doe
So in practice with MySQL that could be used as the following:
$query = "SELECT * FROM client WHERE name LIKE '%" . $name[0] . "%' AND name LIKE '%" . $name[1] . "%'";
For more information on the explode() function, check out the PHP manual at: http://php.net/manual/en/function.explode.php
Hope this helps!
My code let me perform search, as long as the order of the words is correct.
Let's say I'm searching for big dog, but I also want to search for dog big. It get more complicated with 3 or more words.
Is there a way to create a SQL query which would let me search through values with any order?
Only way I can think of this is by having multiple queries, where I change order of PHP variables manually...
<?php
if(isset($_GET['query']) && !empty($_GET['query'])) {
$query = $_GET['query'];
$query_array = explode(' ', $query);
$query_string = '';
$query_counter = 1;
foreach($query_array as $word) {
$query_string .= '%' . $word . (count($query_string) == $query_counter++ ? '%' : '');
}
$query = "SELECT * FROM pages WHERE Name LIKE '$query_string'";
$result = sqlsrv_query($cms->conn, $query);
while($row = sqlsrv_fetch_array($result)) {
extract($row);
echo ''.$Name.'<br>';
}
sqlsrv_free_stmt($stmt);
}
else {
//echo 'NO GET';
}
?>
You could assemble your conditions and check for each word on it's own:
$query_array = explode(' ', $query);
$queryParts = array();
foreach ($query_arra AS $value){
$queryParts[]="Name like '%".mysql_real_escape_string($value)."%'";
}
$searchString = implode(" AND ", $queryParts);
The Search string would now be Name like '%big%' AND Name like '%dog%' ... depending on how much search-keywords have been there.
I use the same approach very often, also when it is required that ALL keywords appear in at least ONE of the columns. Then you need one more loop to create the required AND conditions:
$search = "Big Dog";
$keywords = explode (" ", $search);
$columns = array("Name", "description");
$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;
this would produce the query part (Name like '%Big%' OR description like '%Big%') AND (Name like '%Dog%' or description like '%Dog%')
So, it will find any row, where dog and big are appearing in at least one of the columns name or description (could also be both in one column)
Since your original querystring is something like %big%dog%, so I assume you are okay with matching big wild dog. In this case, you can just use the AND operator.
(Name LIKE '%big%" and Name LIKE '%dog%")
myisam supports full text search:
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
One thing you could look into is Full Text Search for ms sql server.
https://msdn.microsoft.com/en-us/library/ms142571.aspx
it's similar to a "search engine" in that it works off of an algorithm to rank results and even similar words (think thesaurus type lookups)
It's not exactly trivial to set up, but it's easy enough to find a tutorial on the subject and how to query from FTS (as the syntax is different than say LIKE '%big%dog%')
Here's a sample query from the page linked above:
SELECT product_id
FROM products
WHERE CONTAINS(product_description, ”Snap Happy 100EZ” OR FORMSOF(THESAURUS,’Snap Happy’) OR ‘100EZ’)
AND product_cost < 200 ;
I have a user query and a database. My database contains tables. What I am curious to know, is my method for querying the database. What I'm thinking is:
Separate the query into an array split by a space
Loop through each word and do a LIKE '%{$word}%' OR
Above that, just prior to each iteration, do an 'AND'
The problem is, its not working correctly. Its not dicing done to precise emails that match my queries. Here is my code:
$i=0;
$userQuery = $_POST['q']; // q = "Jonathan gmail"
$sql = "SELECT * FROM addresses WHERE ";
$parts = explode(' ',$userQuery);
$cnt=count($parts);
foreach($parts as $part){
$part = mysql_real_escape_string($part);
if($i!==$cnt-1){
$sql.="(
addresses.name LIKE '%".$part."%' OR
addresses.localpart LIKE '%".$part."%' OR
addresses.domain LIKE '%".$part."%'
) AND
";
} else {
$sql.="(
addresses.name LIKE '%".$part."%' OR
addresses.localpart LIKE '%".$part."%' OR
addresses.domain LIKE '%".$part."%'
)
";
}
$i++;
}
}
My question is whats wrong with this logic? It seems accurate.
First of all: This will break on a single word.
Second: This is everything else but safe from an SQL attack.
Now - how I'd do it
$parts = preg_split('/[\s,]+/',$userQuery);
$sql=array();
foreach($parts as $part) {
$part=mysql_real_escape_string($part); //Or whatever works with your DB access framework
$sql[]="(addresses.name LIKE '%$part%' OR addresses.localpart LIKE '%$part%' OR addresses.domain LIKE '%$part%')";
}
$sql=implode(' AND ', $sql);
$sql="SELECT * FROM addresses WHERE $sql";
hey something like this:
foreach($parts as $key => $part){
$part=mysql_real_escape_string($part);
$sql .= sprintf("(
addresses.name LIKE %s OR
addresses.localpart LIKE %s OR
addresses.domain LIKE %s
)", $part);
if ($key!=($cnt-1)) {
$sql .= " AND ";
}
}
Little notice, you're using $i variable before initializing it. Also maybe it will be a better way to use REGEXP. Something like:
// $search_terms = '%Jonathan%|%gmail%'
$sql = "addresses.name REGEXP $search_terms OR addresses.localpart REGEXP $search_terms OR addresses.domain REGEXP $search_terms";
More details on REGEXP
I face a problem with the str_replace function, see the code below :
$query = "SELECT title FROM zakov WHERE chnt='$atd_nad'";
$str = str_replace("Example.com_", "","$query");
$result = mysql_query($str) or die('Errant query: '.$str);
What I want is to replace the word " Example.com_ " with nothing "" but it did not work for me ! I do not know why.
In the row 'title' you can find something like this " Example.com_nameofsmthng "
So what I want is to keep just the word "nameofsmthng" and also to keep the begining of each word of it in capital letter to have finally somethin like "NameOfSmthng"
$atd_nad = 'Foobar Example.com_nameofsmthng Bazbat';
$query = 'SELECT title FROM zakov WHERE chnt="' . $atd_nad . '"';
$str = str_replace('Example.com_', '', $query);
echo $str; // SELECT title FROM zakov WHERE chnt="Foobar nameofsmthng Bazbat"
This works fine. Try it quickly. My assumption is that you mistyped $atd_nad or the value is incorrect.
Edit: hmm i think I misunderstood the example your trying to replace the string in the query string instead of the database?
You could make mysql do the replacement for you which should be faster then making php do it.
$query = "SELECT REPLACE(title, 'Example.com_', '') as newtitle FROM zakov WHERE chnt='$atd_nad'";
$resultset = mysql_query($query) or die('Errant query: '.$query);
$result = mysql_fetch_assoc($query);
echo $result['newtitle'];
Or you could replace all occurrences in the database with an update and then just select the title.
UPDATE zakov SET title = REPLACE(title, 'Example.com_', '');
Hope this helps.
while($row = mysql_fetch_assoc($result)) {
$title = str_replace("something", "", $row['title']);
}
Is what I believe you're looking for. Your code is trying to replace it in the query, which doesn't make sense. You need to replace it in the actual records. This will replace "something" with "". Alternatively, if you've already stored them in an an array or something you would just loop over the array and do the replacement. Basically: operate on the records, not on the query.
i have a variable and an user_name i want to search on a string(function_description) of the user_name for it
whats wrong with this :
$function_keywords = mysql_real_escape_string($_POST['function_keywords']);
if($function_keywords=="" || empty($function_keywords)){
redirect("show.php?functions=PHP");
}
//trim whitespace from the stored variable
$trimmed = trim($function_keywords);
//separate key-phrases into keywords
$trimmed_keywords = explode(" ",$trimmed);
// Build SQL Query for each keyword entered
foreach ($trimmed_keywords as $trimm){
// MySQL "MATCH" is used for full-text searching.
//this code is ebv weird , should check out soon!
$query = "SELECT *
FROM functions
WHERE isEnabled=1 AND isPrivate=0
AND function_description LIKE '{$trimm}'
AND user_name='{$user_name}'
";
// Execute the query to get number of rows that contain search kewords
$results=mysql_query ($query,$connection);
as far as "like" syntax goes you have to use the '%' symbol. if you query for
select * from table where column like '%yourkeyword%'
then it returns any rows with 'yourkeyword' inside the table column.
your statement will be true only if the column = 'yourkeyword'
That's highly inefficient. If someone puts in 5 keywords, you'd be running the search 5 times and getting 5 sets of results. Try something more along these lines:
$words = $_POST['function_keywords'];
if ($words == '') {
... abort ...
}
$parts = trim(explode(' ', $words));
$clauses = array();
foreach($parts as $part) {
$clauses[] = "function_description LIKE '%" . mysql_real_escape_string($part) . "%'";
}
$clause = implode(' OR ' , $clauses);
$sql = "SELECT .... WHERE (isEnabled=1) AND (isPrivate=1) AND (user_name='$user_name') AND ($clause)";
$result = mysql_query($sql) or die(mysql_error());
This'll build up a long series of or statements for each keyword specified, and run the whole thing as a single query.
To see if the function_description contains the keyword you need to use '%' which stands for anything much the way '*' does in unix. Try function_description LIKE '%{$trimm}%'