0

Ok so I'm pretty new to PHP and building a question/answer site. I want a page where the user can search my questions table to find a question and after some research and work I've come up with this but my problem is common words. If a user types "is" in the search every question with "is" in it turns up. My question is either 1) Is my approach to this search function completely wrong? or 2) is there a way I can inject an array of common words to be omitted from the query?

search_reslut.php:

<?php


$servername = "127.0.0.1";
$username = "dylan326";
$password = "";
$dbname = "questions87";
$port = 3306;

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname, $port);
// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
} 

echo "Your search results: <br>";
echo "<br />";
$query = $_POST['query'];

$query  = "$query $query $query";
$pieces = explode(" ", $query);
$qindex0 = $pieces[0]; // piece1
$qindex1 = $pieces[1]; // piece2
$qindex2 = $pieces[2]; // piece3
$qindex3 = $pieces[3];
$qindex4 = $pieces[4];
$qindex5 = $pieces[5];
$qindex6 = $pieces[6];



echo $query;

$sql = "select q_id, question, username, q_date from questions where (question like '%$qindex0%' or question like '%$qindex1%' or question like '%$qindex2%' or question like '%$qindex3%'
or question like '%$qindex4%' or question like '%$qindex5%' or question like '%$qindex6%')";



$result = $conn->query($sql);

if (mysqli_num_rows($result) > 0) {
    // output data of each row
    while($row = mysqli_fetch_array($result)){

        $question = $row['question'];

echo ('<a href="totalqs.php?q_id=' . $row['q_id'] .'" >' . $question .'Asked by:'.' '.$row['username'].' '.$row['q_date'] .' </a>'  . '<br>');


}}

else {echo "No resluts found";}




?>
do734
  • 37
  • 9
  • 2
    There are quite a lot of problems with this script. But I'm bored anyway so I'll rewrite the whole thing for you. May take a while though. – icecub Jul 24 '17 at 23:16
  • The thing you want to learn about is called "stop words." They are the words that are not part of the important vocabulary. https://en.wikipedia.org/wiki/Stop_words These are often kept in an object or array and are used to filter words from the collection of all words in the document. – Ray Paseur Jul 24 '17 at 23:22
  • I'm serious. Already working on it. Commenting inside the code to explain everything :) – icecub Jul 24 '17 at 23:24
  • Ok, since I don't have your database, I'm unable to actually check if the code works. Could you please test it out? https://pastebin.com/KfrZt8Yy – icecub Jul 25 '17 at 00:15
  • getting: "Fatal error: Wrong SQL: Error: 1065 Query was empty in /home/ubuntu/workspace/question_practice/search_result.php on line 88" – do734 Jul 25 '17 at 00:24
  • Oh crap. Ye I know the problem. `$sql` must be `$query` everywhere in the code – icecub Jul 25 '17 at 00:26
  • Nah. Just change these 2 lines: `$stmt = $conn->prepare($query);` and `trigger_error('Wrong SQL: ' . $query . ' Error: ' . $conn->errno . ' ' . $conn->error, E_USER_ERROR);` – icecub Jul 25 '17 at 00:26
  • I'm not sure about the num_rows btw. Could be that you need to change `$cnt = $res->num_rows;` to `$cnt = $stmt->num_rows;`. You'll have to try it if it keeps popping up no results found. – icecub Jul 25 '17 at 00:30
  • I don't have enough reputation to chat and they don't want me to comment too much more but this is some intense code and good for studying. I really appreciate the help! I'll eventually get this to work. If there was a way to give you a point or something here I would. Thanks again! – do734 Jul 25 '17 at 00:32
  • No problem :) I'm just not posting it as an anwer because it's untested. And you can simply delete any of your comments that are no longer needed. Like the feedback you gave me on the code :) – icecub Jul 25 '17 at 00:34
  • Just when I was about to post my answer, Shadow closed the question. Anyway, here's the fully working (tested) code: https://pastebin.com/iz5by3Hu – icecub Jul 25 '17 at 01:55
  • Hey thanks a lot! I'm still getting an error and I think it's because of the query. this is not a complete sql query is it? – do734 Jul 25 '17 at 17:39
  • $query = 'SELECT q_id, question, username, q_date FROM questions WHERE (question '; – do734 Jul 25 '17 at 17:39
  • I tried this but it still does not work $query = "SELECT q_id, question, username, q_date FROM questions WHERE question like '%$search%'"; – do734 Jul 25 '17 at 17:40
  • Nevermind! I see what you were doing ther and It does work. Thanks! – do734 Jul 25 '17 at 19:21

1 Answers1

3

MySQL has the ability to make keyword searches easy and much faster than what you're doing. This is done through the MATCH(column) AGAINST ('words to search') syntax. Add a FULLTEXT index to your table, for the column you want to make searchable (question). Then something like this would work to return all questions that have at least one of the search words

// Get the query. escape all single quotes.
$words = str_replace("'","\'",$_POST['query']);

$sql = <<< "SQL"
select q_id, question, username, q_date from questions 
where MATCH(`question`) AGAINST('$words' IN BOOLEAN MODE)
SQL;

$result = $conn->query($sql);

The nice thing about FULLTEXT searches is that they automatically exclude common words (stop words) from the searches for you. Learn more here as well as here

If you have a custom list of stop words, you can just remove them from the $words string before you execute the query

$stopWords = [
  '/is/', 
  '/the/'
];

// Where is the cat   >> Where   cat
$words = preg_replace($stopWords,'',$words);

Note from the docs:

Full-text indexes can be used only with MyISAM tables. (In MySQL 5.6 and up, they can also be used with InnoDB tables.) Full-text indexes can be created only for CHAR, VARCHAR, or TEXT columns.

BeetleJuice
  • 39,516
  • 19
  • 105
  • 165
  • Yes I was seeing some stuff about match aginst, I'll work on this and see if I can get it working. Thank you. – do734 Jul 24 '17 at 23:37
  • I'm getting this error "Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in /home/ubuntu/workspace/question_practice/search_result.php on line 56" when I try to plug this in. Does my if statement need to be altered as well? – do734 Jul 25 '17 at 00:12
  • this is line 56: if (mysqli_num_rows($result) > 0) – do734 Jul 25 '17 at 00:13
  • @do734 It means that the query did not execute successfully. look up how to get the error message from a failed mysqli query and investigate yourself (something like `if(!$result) echo mysqli_error()`. – BeetleJuice Jul 25 '17 at 01:42
  • Ok thanks I'll do that. – do734 Jul 25 '17 at 15:42
  • I've realized my problem is that I'm using innodb and it does not support fulltext indexes. I could change to myISAM but I think how my foreign/primary key's are set up I need innodb? – do734 Jul 25 '17 at 17:36
  • FULLTEXT indices can be used with InnoDb tables in MySQL version 5.6+. If your version doesn't support FULLTEXT, I would do something different. I would not switch to MyISAM – BeetleJuice Jul 25 '17 at 21:51