multiple terms SQL with explode/implode and PHP PDO - php

I have a search form that would like the users to search multiple terms. I'm currently using PHP PDO and I'm still learning... I was wondering if someone can tell me what I'm doing wrong here.
$varSearch = #$_GET['dms'];
$varTerm = explode(" ", $varSearch);
$termArray = array();
foreach($varTerm as $term){
$term = trim($term);
if(!empty($term)){
$termArray[] = "name LIKE '%".$term."%' OR tags LIKE '%".$term."%'";
}
}
$implode = implode(' OR ', $termArray);
$sql = $dbh->prepare("SELECT * FROM table WHERE ?");
$sql->execute(array($implode));

Have you considered doing something like this, instead:
$varSearch = #$_GET['dms'];
$varTerm = explode(" ", $varSearch);
$termsStringArray = array();
$termsArray = array();
foreach($varTerm as $term){
$term = trim($term);
if(!empty($term)) {
array_push($termsStringArray, "name LIKE ? OR tags LIKE ? ");
array_push($termsArray, $term);
array_push($termsArray, $term); // note, you can do this part differently, if you'd like
}
}
$implodedTermsString = implode('OR ', $termsStringArray);
$sql = $dbh->prepare("SELECT * FROM biz WHERE " . $implodedTermsString);
$sql->execute(array($termsArray));
Output:
// prepare statement
SELECT * FROM biz WHERE name LIKE ? OR tags LIKE ? OR name LIKE ? OR tags LIKE ? OR name LIKE ? OR tags LIKE ? OR name LIKE ? OR tags LIKE ?
// $termsArray (for execute)
Array
(
[0] => this
[1] => this
[2] => is
[3] => is
[4] => the
[5] => the
[6] => string
[7] => string
)
Basically, trying to separate the array data from the initial SQL query prepare string. Let me know if that works for you!
Though, you still will want to do some sort of checking (or sanitization,) of the data you are getting from the $_GET variable. That $_GET variable could have anything in it... and could be bad for SQL injections or other unwanted issues.
And, LIKE isn't necessarily going to be the most efficient way to do this type of database search. But if you use it (and I have used it for search things in the past,) try checking out: http://use-the-index-luke.com/sql/where-clause/searching-for-ranges/like-performance-tuning.

If anyone else needs this answer too...
$varSearch = #$_GET['dms'];
$varTerm = explode(" ", $varSearch);
$termArray = array();
foreach($varTerm as $term){
$term = trim($term);
if(!empty($term)){
$termArray[] = "name LIKE :term OR tags LIKE :term";
}
}
$implode = implode(' OR ', $termArray);
$sql = $dbh->prepare("SELECT * FROM table WHERE ".$implode."");
$sql->execute(array(":term"=>"%".$term."%"));

Remake
$my_explode = explode(" ",$search);
$query = array();
foreach($my_explode as $string)
{
$query[] ="name LIKE '%".$string."%' OR email LIKE '%".$string."%'";
}
$implode = implode(' OR ', $query);
foreach ($db->query("SELECT * FROM _table WHERE ".$implode."") as $info)
{
echo $info['name']."<br />";
}
Secure for injection, with php retrieve just alphanumeric chars
$search = preg_replace("/[^a-zA-Z0-9]+/", "-", $_GET["text"]);

Related

How to find a database row that matches a string?

I have a databse table with 100K rows and an array of 100 items. And I need to find if an array item is found in my Users table username row.
My database table Users
| id | username | fullname |
1 John John Smith
2 Elliot Jim Elliot
3 Max Max Richard
My array looks like this
[
{
string: 'Hello, this is Elliot from downtown Las Vegas!'
},
{
string: 'Hey how are you?'
}
]
My idea was to do a foreach loop through every row in my Users table (100k records) and find if it matches in my array, but it is so slow.
foreach ($MyArray as $Array) {
foreach ($dbrows as $dbrow) {
if (strpos($Array['string'], $dbrow['username']) !== false) {
echo 'found it!';
break;
}
}
}
It will be a bit hit and miss as you may find users with all sorts of weird names that match normal words, this approach splits the input into words and then uses them to form an in clause to search the database. So it only looks at records that match rather than all records...
$search = 'Hello, this is Elliot from downtown Las a1 Vegas!';
$words = str_word_count($search, 1);
$bind = str_repeat("?,", count($words));
$bind = trim($bind, ",");
$query = $conn->prepare("select * from users where username in ($bind)" );
$types = str_repeat("s", count($words));
$query->bind_param($types, ...$words);
$query->execute();
$res = $query->get_result();
while($row = $res->fetch_assoc()) {
// Process result
}
It also uses prepared statements, which is where all of the $bind and $types processing comes in. If you look at $query you will see how it's built up.
I think the better way was to separate your search arrays into words, and use it in the query, like:
<?php
// Assuming your search array is $search...
$words = array ();
foreach ( $search as $text)
{
$words = array_merge ( $words, explode ( " ", trim ( preg_replace ( "/[^0-9a-z]+/i", " ", $text))));
}
$words = array_unique ( $words);
$in = "";
foreach ( $words as $text)
{
$in .= ",'" . $mysqli->real_escape_string ( $text) . "'";
}
if ( ! $result = $mysqli->query ( "SELECT * FROM `Users` WHERE `username` IN (" . substr ( $in, 1) . ")"))
{
echo "MySQL error!";
}
// Results at $result
?>
You can use regular expressions:
<?php
$query_string = "bla bla bla...";
$qry = $mysqli_query($conn, "SELECT *FROM table WHERE username REGEXP '$query_string'");
?>
Regular expression matches data individually from table.

how to split a string into substring using php [duplicate]

This question already has answers here:
How can I bind an array of strings with a mysqli prepared statement?
(7 answers)
Closed 6 months ago.
I have a string like this 'dubai,sharjah,' and I want to make it like this 'dubai','sharja',
I am passing the value dubai,sharjah, in the URL using ajax and my code
$city=$_GET['city'];
$sql = "SELECT * FROM filter where isdeleted = 0 ";
if ($city !="" && $city !="Empty" ){
$sql.=" and twon in ('".$citydata."')";
}
when I print the query, it's like this
SELECT * FROM filter where isdeleted = 0 and twon in ('dubai,sharjah,')
but I want it like this
SELECT * FROM filter where isdeleted = 0 and twon in ('dubai','sharja')
Can anyone guide me on how to do this using PHP?
Here's how I would approach it. I'm going to use PDO instead of mysqli because trying to get an array into mysqli_stmt::bind_param is just a pain.
First, create an array of cities, removing any empty values
$params = array_filter(explode(',', $city), function($c) {
return !empty($c) && $c !== 'Empty';
});
$paramCount = count($params);
$query = 'SELECT * FROM filter where isdeleted = 0';
Now generate a placeholder string for your prepared statement.
if ($paramCount) {
$placeholders = implode(',', array_fill(0, $paramCount, '?');
// looks something like '?,?'
$query .= " AND twon IN ($placeholders)";
}
Now, prepare a statement
// assuming you have a PDO instance in $pdo created with something like
// $pdo = new PDO('mysql:host=localhost;dbname=your_db;charset=utf8', 'username', 'password', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$stmt = $pdo->prepare($query);
Execute and fetch values :)
$stmt->execute($params);
$filters = $stmt->fetchAll(PDO::FETCH_ASSOC);
$cities = explode(",", $_GET['city']);
//escape!
foreach ($cities as $citykey => $city) {
$cities[$citykey] = "'" . mysql_real_escape_string($city) . "'";
}
$sql = "SELECT * FROM `filter` where `isdeleted` = 0";
if (!empty($cities)) {
$sql .= ' and `twon` in (' . implode(',', $cities) . ')';
}
An alternative is to use FIND_IN_SET(). No PHP code change needed.
$sql.=" and FIND_IN_SET(town, '".$citydata."')";
you can try to explode the string
$cityparts = explode(",",$city);
and you can use
$cityparts[0] and $cityparts[1] in your query
array explode ( string $delimiter , string $string [, int $limit ] )
you can find more information on [http://www.php.net/explode]
hope this helps!!
You just have to explode and implode here. Rest is the problem with extra , in your string at the end.
$str = "dubai,sharjah,";
$citydata = implode("','",explode(',',rtrim($str,',')));
echo "'$citydata'";
test
After 6 answers I gotta add a 7th:
$sql.=" and twon in ('".str_replace(",","','",$citydata)."')";
You can do this.
$string = 'dubai,sharjah';
$cities = explode(',', $string);
echo $cities[0]; //dubai
echo $cities[1]; //sharjah
try this
$str = "dubai,sharjah,";
$arr = explode(",", $str);
$arr_temp = array()
foreach($arr as $s)
{
if($s!="")
{
$arr_temp[] = "'".$s."'";
}
}
$new_str = implode(",", $arr_temp);
echo $new_str; // output 'dubai','sharjah'
Now your Sql will be
$sql = "SELECT * FROM filter where isdeleted = 0 and twon in ($new_str) ";
You can use it
in $city I fix two values with, you can use here by $_GET ;
$city = "dubai,sharjah,";
$query_string ="";
$words = explode(",",$city);
for($i=0;$i<count($words);$i++){$query_string .= "'".$words[$i]."',";}
$query_string = substr($query_string,0,strlen($query_string)-4);
then use your query
SELECT * FROM filter where isdeleted = 0 and twon in ($query_string)
if ($city !="" && $city !="Empty" )
{
$city_exp = explode(',' $city);
$sql .= " and twon in ('".implode("', '", $city_exp)."')";
}
What we are basically doing here is putting the two values in an array by using explode and then separating each item in that array by using implode
DEMO

How to search mysql from php

I have a query from user to search in mysql database
<input type="text" name="query_textbox"><input type="submit" name="search_button">
<?php
if (isset($_GET['search_button']))
{
$query = $_GET['query_textbox'];
$command = "SELECT * FROM `table` WHERE `ProteinName` LIKE '%$query%';";
$result = mysql_query($command);
echo $result;
}
?>
When I put 'human' in textbox then it works. But when I search for 'human protein' it shows 0 results.
Now the question is "if I search for a query including whitespaces like 'human protein', it should show me result for 'human protein' as well as for 'human' and for 'protein'. How to do that?
You could do something like this:
$query = $_GET['query_textbox'];
// explode the query by space (ie "human protein" => "human" + "protein")
$keywords = preg_split("#\s+#", $query, -1, PREG_SPLIT_NO_EMPTY);
// combine the keywords into a string (ie "human" + "protein" => "'%human%' OR '%protein%'")
$condition = "'%" . implode("%' OR '%", $keywords) . "%'";
$command = "SELECT * FROM `table` WHERE `ProteinName` LIKE $condition;";
$query = $_GET['query_textbox'];
// explode the query by space (ie "human protein" => "human" + "protein")
$keywords = explode(" ", $query);
foreach($keywords as $key => $value){
$condition[] = `ProteinName` LIKE "'%".$value."%'"
}
$cond_str = implode(' OR ', $condition);
$command = "SELECT * FROM `table` WHERE $cond_str;";

How would I sort this array [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How to sort the results of this code?
Im making a search feature which allows a user to search a question and it will show the top 5 best matching results by counting the number of matching words in the question.
Basically I want the order to show the best match first which would be the question with the highest amount of matching words.
Here is the code I have.
<?php
include("config.php");
$search_term = filter_var($_GET["s"], FILTER_SANITIZE_STRING); //User enetered data
$search_term = str_replace ("?", "", $search_term); //remove any question marks from string
$search_count = str_word_count($search_term); //count words of string entered by user
$array = explode(" ", $search_term); //Seperate user enterd data
foreach ($array as $key=>$word) {
$array[$key] = " title LIKE '%".$word."%' "; //creates condition for MySQL query
}
$q = "SELECT * FROM posts WHERE " . implode(' OR ', $array); //Query to select data with word matches
$r = mysql_query($q);
$count = 0; //counter to limit results shown
while($row = mysql_fetch_assoc($r)){
$thetitle = $row['title']; //result from query
$thetitle = str_replace ("?", "", $thetitle); //remove any question marks from string
$title_array[] = $thetitle; //creating array for query results
$newarray = explode(" ", $search_term); //Seperate user enterd data again
foreach($title_array as $key => $value) {
$thenewarray = explode(" ", $value); //Seperate each result from query
$wordmatch = array_diff_key($thenewarray, array_flip($newarray));
$result = array_intersect($newarray, $wordmatch);
$matchingwords = count($result); //Count the number of matching words from
//user entered data and the database query
}
if(mysql_num_rows($r)==0)//no result found
{
echo "<div id='search-status'>No result found!</div>";
}
else //result found
{
echo "<ul>";
$title = $row['title'];
$percentage = '.5'; //percentage to take of search word count
$percent = $search_count - ($search_count * $percentage); //take percentage off word count
if ($matchingwords >= $percent){
$finalarray = array($title => $matchingwords);
foreach( $finalarray as $thetitle=>$countmatch ){
?>
<li><?php echo $thetitle ?><i> <br />No. of matching words: <?php echo $countmatch; ?></i></li>
<?php
}
$count++;
if ($count == 5) {break;
}
}else{
}
}
echo "</ul>";
}
?>
When you search something it will show something like this.
Iv put the number of matching words under each of the questions however they are not in order. It just shows the first 5 questions from the database that have a 50% word match. I want it to show the top 5 with the most amount of matching words.
What code would I need to add and where would I put it in order to do this?
Thanks
Here's my take on your problem. A lot of things have been changed:
mysql_ functions replaced with PDO
usage of anonymous functions means PHP 5.3 is required
main logic has been restructured (it's really hard to follow your result processing, so I might be missing something you need, for example the point of that $percentage)
I realize this might look complicated, but I think that the sooner you learn modern practices (PDO, anonymous functions), the better off you will be.
<?php
/**
* #param string $search_term word or space-separated list of words to search for
* #param int $count
* #return stdClass[] array of matching row objects
*/
function find_matches($search_term, $count = 5) {
$search_term = str_replace("?", "", $search_term);
$search_term = trim($search_term);
if(!strlen($search_term)) {
return array();
}
$search_terms = explode(" ", $search_term);
// build query with bind variables to avoid sql injection
$params = array();
$clauses = array();
foreach ($search_terms as $key => $word) {
$ident = ":choice" . intval($key);
$clause = "`title` LIKE {$ident}";
$clauses []= $clause;
$params [$ident] = '%' . $word . '%';
}
// execute query
$pdo = new PDO('connection_string');
$q = "SELECT * FROM `posts` WHERE " . implode(' OR ', $clauses);
$query = $pdo->prepare($q);
$query->execute($params);
$rows = $query->fetchAll(PDO::FETCH_OBJ);
// for each row, count matches
foreach($rows as $row) {
$the_title = $row->title;
$the_title = str_replace("?", "", $the_title);
$title_terms = explode(" ", $the_title);
$result = array_intersect($search_terms, $title_terms);
$row->matchcount = count($result);
}
// sort all rows by match count descending, rows with more matches come first
usort($rows, function($row1, $row2) {
return - ($row1->matchcount - $row2->matchcount);
});
return array_slice($rows, 0, $count);
}
?>
<?php
$search_term = filter_var($_GET["s"], FILTER_SANITIZE_STRING);
$best_matches = find_matches($search_term, 5);
?>
<?php if(count($best_matches)): ?>
<ul>
<?php foreach($best_matches as $match): ?>
<li><?php echo htmlspecialchars($match->title); ?><i> <br/>No. of matching words: <?php echo $match->matchcount; ?></i></li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<div id="search-status">No result found!</div>
<?php endif; ?>
Try adding asort($finalarray); after your $finalarray = array($title => $matchingwords); declaration:
...
if ($matchingwords >= $percent){
$finalarray = array($title => $matchingwords);
asort($finalarray);
....
It should sort your array Ascending by the Values

Mysql Results and array manipulation

I am stuck working on a problem, and would appreciate some guidance. I am working with an old system that was coded awfully, and didnt do any validating, or sanitzing of user input, so the database I'm working with is a bit missy.
I have issues with one column called "tags", used for tags for articles. But each row appears like this, and varies between them:
tag tag1 tag2 tag3
OR
tag1, tag2, tag
But I need to combine them and put them into an array that lists them by how many times each one occurs, like this:
tag(2)
tag1(2)
tag2(2)
tag3(1)
Because I'm not the most astute with php, Im not sure if I am going about the problem correctly?
Im new to manipulating arrays on this scale which is why I am stuck at this point. You can view the example below of what I am doing below:
$sql = "SELECT tags, approved FROM articles WHERE approved = '1' ";
$result = mysql_query($sql);
while( $rows = mysql_fetch_array($result) ) {
$arr = $rows['tags'];
$arr = str_replace(", ", " ", $arr); // attempting to clean up the data, so that each word appends with a space.
$arr = str_replace(" ", " ", $arr);
// Don't know what to do next, or if this is even the right way to do it.
}
Any help is appreciated.
Thanks, Lea
Maybe this will be helpful. Modified your code to have a $tagArr for each query. If you need an overall array of tags it would be a bit different, but could easily be coded using the following.
while( $rows = mysql_fetch_array($result) ) {
$arr = $rows['tags'];
$arr = str_replace(", ", " ", $arr); // attempting to clean up the data, so that each word appends with a space.
// Don't know what to do next, or if this is even the right way to do it.
$tagArr = array();
$current_tags = explode(" ", $arr);
foreach($current_tags as $tag) {
if(!array_key_exists($tag, $tagArr)) {
$tagArr[$tag] = 1;
} else {
$tagArr[$tag] = $tagArr[$tag]++;
}
}
// now $tagArr has the tag name as it's key, and the number of occurrences as it's value
foreach($tagArr as $tag => $occurrences) {
echo $tag . '(' . $occurrences . ')<br />';
}
}

Categories