PHP search multiple fields issue - php

I'm working through this tutorial online: http://goo.gl/qnk6U
The database table: ajax_search
Firstname | Lastname | Age | Hometown | Job
-------------------------------------------
Joe | Smith | 35 | Boulder | CIA
Steve | Apple | 36 | Denver | FBI
(Types are all varchar except age is an int.)
My question. Is the sql select statement below written correctly to query "Joe 35"? For some reason, I can only query "Joe" and it works, but not combining search terms.
$sql = "select * from ajax_search where FirstName like '%$rec%' or LastName like '%$rec%' or Age like '%$rec%' or Hometown like '%$rec%'";

Assuming your query is "Joe 35", then no. Your query matches any row where any of the four fields contains "Joe 35" (in a single field). To query for a user with name Joe and age 35, you'd need to split the search query and do something like:
WHERE Firstname LIKE "$firstname" AND Age LIKE "$age"

You need to split that sting from search query:
$columns = array("Firstname", "Lastname", "Age", "Hometown", "Job");
$string = ""; // acquire query string
$split = explode(" ", $string);
$search_words = array();
foreach ($split as $word) {
$search_words[] = $word;
}
Create query to search all over the fields:
$first = true;
$sql = "select * from ajax_search where";
foreach ($search_words as $word) {
foreach ($columns as $col) {
$sql .= (($first) ? " " : " OR") . "`$col` LIKE \"%" . $word . "%\"";
$first = false;
}
}
Then run this query.
Another and also a better solution would be more complicated word(tag) based indexing, because this can generate morbid queries when used with more words.

Related

Search bar should ignore “-”, Caps and spaces (132D123 and 132 d 123 should return true) ? php

Currently when i search the registration number 131-D-12345 I have to type the hyphens to get the results, but I wish to ignore “-”, caps and spaces (so for instance "132D123" and "132 d 123" should return true).
How can I do that in PHP?
<?php
require('/home/s3022041/sqlC/dbConnect.php');
if(isset($_POST['searchById']))
{
$search = mysqli_real_escape_string($connection, $_POST['get_id']);
$id = $_POST['get_id'];
$query = "SELECT * FROM cars WHERE Registration_Number = '$id' ";
$query_run = mysqli_query($connection, $query);
?>
If I understood your question correctly
Your database looks something like this example
1 | 987-D-987
2 | 654-E-456
3 | 789-D-123
4 | 678-Z-123
And for example,if you search for 654 e 456 you are expecting to get entry 2.
Well you could use good old string functions...
<?php
$id = $_POST['get_id'];
$stp1 = preg_replace("/[^a-zA-Z0-9]/", "", $id); //grab only the alphanumerics
$stp2 = strtoupper($stp1); //Make all alphabets uppercase
$stp3 = preg_replace('/\d+/', '',$stp2); //extract the alphabets part
$newsearchid = str_replace($stp3,"-".$stp3."-",$stp2); //put hyphens before and after the alphabet part
echo "spaces or lower case .i will return this".$newsearchid; //now the search string looks like one in the database
require('/home/s3022041/sqlC/dbConnect.php');
if(isset($_POST['searchById']))
{
$search = mysqli_real_escape_string($connection, $newsearchid);
$query = "SELECT * FROM cars WHERE Registration_Number = '$newsearchid' ";
$query_run = mysqli_query($connection, $query);
?>
if you search for "987 d 987" or "987 d987" or "987d987" or "987D987" or "987-d-987" or "987,d#987" you will still get entry 1 from db.
Basically any search in the format [number][alphabet][number] will always return true
Do I understand correctly that the registration numbers in the database dò contain the hyphens ?
In that case, you should modify your query to hold wildcards (e.g. https://www.guru99.com/wildcards.html)
As for the case, either convert the case of the PHP variable before entering it in the query ( strtoupper(), strtolower() ), or try to solve your case in your table definition.
If the database entries do not hold the hyphens, you can filter them out the variable using a replace or preg_replace() to remove them.
Edit
if I assume your database holds very uniform inputs, like this :
ID | registration
----+---------------
1 | 132D123
2 | 234D324
3 | 456D546
4 | 678D123
then you can prepare your search term as follows :
$searchReg = $_POST['get_id'] ; // take your unmodified POST-ed registration
$searchReg = strtoupper($searchReg) ; // make all characters upper-case, as DB entries are all uppercase
$searchReg = preg_replace("/[\s-]?/", "", $searchReg) ; // replace all whitespaces and hyphens by an empty string - i.e. remove them
if(isset($_POST['searchById']))
{
$search = mysqli_real_escape_string($connection, $searchReg);
$id = $searchReg;
...
If however, your database is not formatted very strictly, like :
ID | registration
----+---------------
1 | 132D123
2 | 234d324
3 | 456-D-546
4 | 678-d-123
Then you need to make your SQL query cover the searchterm using wildcards :
$searchReg = $_POST['get_id'] ; // take your unmodified POST-ed registration
$searchReg = preg_replace( "/[\s-]?/", "%", $searchReg) ; // replace all whitespaces and hyphens by a SQL wildcard
if(isset($_POST['searchById']))
{
$search = mysqli_real_escape_string($connection, $searchReg);
$id = $searchReg;
$query = "SELECT * FROM cars WHERE Registration_Number LIKE '" . strtoupper($id) ."' OR Registration_Number LIKE '" . strtolower($id) . "'" ;
...

INSERT array into separate rows MySQL

I have a dynamic Matrix box where users can unlimited drugs, the data comes through like this:
[addindividuals] => [{"Drug":"Calpol","Strength":"100mg","Form":"Liquid","Quantity":"1"},{"Drug":"Paracetamol","Strength":"200mg","Form":"Tablet","Quantity":"16"}]
What I'm trying to achieve is to have each line inserted into a new row (MySQL) and inserts into their relevant columns like so:
Columns: | Drug | Strength | Form | Quantity
Row1 | Calpol | 100mg | Liquid | 1
Row2 |Paracetamol | 200mg | Tablet | 16
I'm guessing its using the exploded function> (I'm a novice) and then sql to insert the strings?
If you have the values as a json string collection, First you need to explode then the string then use a for each to loop through each string then use another for each to make single row. Please have a below code this may help you.
$addindividuals = '{"Drug":"Calpol","Strength":"100mg","Form":"Liquid","Quantity":"1"},{"Drug":"Paracetamol","Strength":"200mg","Form":"Tablet","Quantity":"16"}';
$exploded_array = explode('},',$addindividuals);
$final_query = "INSERT INTO `table_name` (`Drug`,`Strength`,`Form`,`Quantity`) VALUES ";
$exploded_array[0] = $exploded_array[0].'}';
foreach($exploded_array as $exploded_element)
{
$single_row = '(';
$json_decode = json_decode($exploded_element,true);
foreach($json_decode as $key => $value)
{
$single_row .= "'$value',";
}
$single_row = substr($single_row,0,-1);
$single_row .= '),';
$final_query .= $single_row;
}
$final_query = substr($final_query,0,-1);
echo $final_query;

Doctrine search a string in multiple columns

I hope you can help :)
This is how the table looks:
+------------+----------------+------------------+---------+
| firstName | lastName | email | etc... |
+------------+----------------+------------------+---------+
| John | Doe | john#doe.com | etc... |
+------------+----------------+------------------+---------+
| John | Michaels | john#michaels.es | etc... |
+------------+----------------+------------------+---------+
This is how the code looks:
if($_GET['search-customers'] != '') {
$busqueda = $_GET['search-customers'];
$query->andWhere("(c.firstName LIKE '%$busqueda%' OR c.lastName LIKE '%$busqueda%' OR c.email LIKE '%$busqueda%')");
}
With that QUERY:
If I input: John in the search box, it gives me the 2 results.
OK
If I input: John D in the search box, it doesn't give me any result. FAIL
All right, I understand, When I type "John D", it try to find first in firstName (doesn't match) and also it doesn't match lastName or email.
How can I combine them?
The idea its to find the complete string in all possibilities.
Thanks!
I will provide you a different alternative using MySQL's Full-Text Search Functions. Lets begin to prepare the table:
ALTER TABLE persons ADD FULLTEXT (`firstname`, `lastname`);
Now, firstname and lastname are columns to be used by full-text in order to search for matches:
SELECT * FROM persons
WHERE MATCH (firstname,lastname)
AGAINST ('John D' IN NATURAL LANGUAGE MODE);
The result will be:
+------------+----------------+------------------+---------+
| firstName | lastName | email | etc... |
+------------+----------------+------------------+---------+
| John | Doe | john#doe.com | etc... |
+------------+----------------+------------------+---------+
| John | Michaels | john#michaels.es | etc... |
+------------+----------------+------------------+---------+
Why both? Because John (as a word) was found, however John Doe is in the first row because has much similitude with the term of search.
Say, that lets apply this tool with Doctrine. I will assume that your model looks like this:
class Person{
/** #column(type="string", name="firstname")*/
protected $firstName;
/** #column(type="string", name="lastname")*/
protected $lastName;
/** #column(type="string")*/
protected $email;
}
Lets create the search function:
public function search($term){
$rsm = new ResultSetMapping();
// Specify the object type to be returned in results
$rsm->addEntityResult('Models\Person', 'p');
// references each attribute with table's columns
$rsm->addFieldResult('p', 'firstName', 'firstName');
$rsm->addFieldResult('p', 'lastName', 'lastname');
$rsm->addFieldResult('p', 'email', 'email');
// create a native query
$sql = 'select p.firstName, p.lastname, p.email from persons p
where match(p.firstname, p.lastname) against(?)';
// execute the query
$query = $em->createNativeQuery($sql, $rsm);
$query->setParameter(1, $term);
// getting the results
return $query->getResult();
}
Finnally, and example:
$term = 'John D';
$results = search($term);
// two results
echo count($results);
Additional notes:
Before mysql 5.7, Full-Text only can be added just to MyISAM tables.
Only can be indexed CHAR, VARCHAR, or TEXT columns.
When using IN NATURAL LANGUAGE MODE in a search, mysql returns an empty resultse when the results represent < 50% of the records.
Maybe you could use the explode function like this:
$busqueda = $_GET['search-customers'];
$names = explode(' ',$busqueda);
if(count($names)>1){
$query->andWhere("(c.firstName LIKE '%{$names[0]}%' AND c.lastName LIKE '%{$names[1]}%')");
}else{
$query->andWhere("(c.firstName LIKE '%$busqueda%' OR c.lastName LIKE '%$busqueda%' OR c.email LIKE '%$busqueda%')");
}
but, using like %word% is inefficient, because it can't use index.
Finally, I decided to concat firstName and lastName. I excluded the email then the query looks like that:
$busqueda = $_GET['search-customers'];
$names = explode(' ',$busqueda);
$hasemail = strpos('#', $busqueda);
if ( $hasemail ) {
$query->andWhere("c.email LIKE '%$busqueda%'");
} else {
$query->andWhere("( CONCAT(c.firstName,' ',c.lastName) LIKE '%$busqueda%' OR c.email LIKE '%$busqueda%')");
}
In your repository you could do something like this:
public function findByTerms($terms) : array
{
$alias = "d";
$qb = $this->createQueryBuilder($alias);
foreach (explode(" ", $terms) as $i => $term) {
$qb
->andWhere($qb->expr()->orX( // nested condition
$qb->expr()->like($alias . ".name", ":term" . $i),
$qb->expr()->like($alias . ".description", ":term" . $i)
))
->setParameter("term" . $i, "%" . $term . "%")
;
}
return $qb->getQuery()->getResult();
}
The Query Builder is able to generate complex queries that scale to your needs

how to select all data from mysql table where column is an array or single and my value match with one item of this array?

Please could someone help me? I want to select all values in mysql table where the column that i want to check get a value is mix with aingle or array of values....... So to be more clear I have a table to store all messages from many sender to one or many reciever....
my functions is
public static function find_messagesTo_by_user_id($mess_to=0) {
global $database;
$mess_to = $database->escape_value($mess_to);
$sql = "SELECT * FROM ".self::$table_name;
$sql .= " WHERE mess_to = '{$mess_to}'";
$sql .= " AND mess_deleted = 0";
$sql .= " ORDER BY mess_created_date DESC";
$result_array = parent::find_by_sql($sql);
return $resultrray;
}
So 'mess_to ' has array and single value .... they are only numbers Like (1, 15, 25 ,26 ,27 , array(1,25, 27) , 31, 42, .......)
Please, i break my head on it :)
I waiting for any help?
Building on #Maluchi's answer. Make sure your data looks like:
| mess_to |
+-----------------+
| ,123, |
| ,123,456,152,1, |
| ,456,567, |
| ,3, |
So surround each value in ,. then you can safely do:
WHERE `mess_to` LIKE "%,{$mess_to},%"
This ensures that $mess_to = 1 will match only the 2nd row, and not the 1st as well.
You could also denormalize your data and make a table to JOIN on.
If I'm reading it correctly, $mess_to is passed into the function and could contain either a single value or it could be passed in an array.
When matching multiple values, the SQL should be looking for a comma-separated list. The where clause needs to be IN the list rather than EQUAL to the list.
Try:
public static function find_messagesTo_by_user_id($mess_to=0) {
global $database;
$mess_to = $database->escape_value($mess_to);
$sql = "SELECT * FROM ".self::$table_name;
$sql .= " WHERE mess_to IN (" . implode(',', $mess_to) . ")";
$sql .= " AND mess_deleted = 0";
$sql .= " ORDER BY mess_created_date DESC";
$result_array = parent::find_by_sql($sql);
return $resultrray;
}
See this line in particular:
$sql .= " WHERE mess_to IN (" . implode(',', $mess_to) . ")";
Code edited with geomagas's comments! (Thank you geomagas!)
asuming your column is like this
| mess_to |
+---------+
| 1 |
| 1,2,3,4 |
| 2 |
| 3 |
you can use the LIKE operator:
$sql .= " WHERE mess_to LIKE '%{$mess_to}%'";
this will match every row where mess_to has the string value of $mess_to (your column data type should be string for this to work).

MySQL search all fileds with codeIgniter active query or alt. escaping (like + equals)

Logged in $Account = 2; $SearchString = "Sally Do";
$search_array = explode(' ',$SearchString);
People table example:
ID | Account | FirstName | LastName | Misc Other
---------------------------------------------------
1 | 1 | John | Doe | Testing
2 | 2 | John | Doe | Pick Me
3 | 2 | Jonh | Bob | Not Me
If possible I would like to search all table fields without the need to specify them and to escape the values for the LIKE or preferably using CodeIgniter's Active Query.
SELECT * FROM poeple WHERE Account = 2 AND
(
PHP
foreach $search_array
{
FirstName LIKE '%svalue%' OR LastName LIKE '%svalue%'
}
)
Escaping breaks the SQL query and I'm sure I'm probably just doing something wrong...
$this->db->escape($search_array[0]);
$this->db->escape($search_array[1]);
I would much prefer a pure active query but I'm not sure it's possible?
$query = $this->db->select('*')->from('people')->where('Account', $Account)->like(???)->get();
The issue mostly with active query is the lack of ( ) support so the Account doesn't become an OR.
Decided to use an existing escaping function (built into CI) to use with a non-Active Query
function escape_string($str, $like = FALSE)
{
if (is_array($str)){
foreach ($str as $key => $val){
$str[$key] = escape_string($val, $like);
}
return $str;
}
mysql_real_escape_string($str);
if ($like === TRUE){
$str = str_replace(array('%', '_'), array('\\%', '\\_'), $str);
}
return $str;
}
try this way
$this->db->select('*');
$this->db->from('people');
$this->db->where('acount',$account);
if($first_name!='')
{
$this->db->like('first_name',$first_name);
}
if($last_name!='')
{
$this->db->like('last_name',$last_name);
}
Try this one.
$where = "(firstname LIKE '%".$value."%' OR lastname LIKE '%".$value."%')";
$this->db->SELECT('*');
$this->db->from('people');
$this->db->where($where);
$this->db->where('account', $account);
$this->db->get();

Categories