Displaying search results with PHP
Posted on 30 August 2006 (03:23 PM)
In this article I will explain how I've accomplished the look of my search results when someone uses the search box on the right. I'm not talking about styling through CSS, but about formatting them on the server-side.
It's all about context
The first time I uploaded my Search page, it displayed the summaries of articles found using your keywords, in the same way they appear on the homepage. I then started thinking how I could improve that look. From my point of view, it's better (and more logical) to not show just a random bit of text associated to the articles found (in this case the introduction), but to show a snippet of the article which contains the keyword, so users may scan over the results even quicker.
It makes sense. Also, people are used to the concept, almost every search engine does the same. So, without further ado;
Cutting up the pieces
I've written a class, Chunk.PHP, which takes three arguments: the subject string, a maximum amount of characters and an array of search words. The Chunk class is very easy to use, see the example below:
require ('Chunk.php');$summ = $row['articleText'];$ch = new Chunk ($summ,300,$words);$summ = nl2br($ch->get());- Download this code: /code/displaying_search_results_with_php1.txt
The variable $summ will now contain a snippet of 300 characters long, containing one of the words in the array (the first match it finds). I've set up a small test case (Javascript required!) for you to test its behaviour.
As you can see, the Chunk class tries to make a match with one of the words in the array and when it does, it takes the 300 characters surrounding it and outputs this snippet using the Chunk->get() method.
Under the hood
Here I will provide some insight in what the Chunk class actually does to your string.
$len = count($searchTerms);$chunk = '';for ($i = 0; $i < $len; $i++){if (preg_match("/$searchTems[$i]/",$str)){$pos = strpos ($str,$searchTerms[$i]);if (($pos - ($maxChar/2)) < 0){$startPos = 0;}else{$startPos = ($pos - ($maxChar/2));$chunk .= '...';}$chunk .= substr($str,$startPos,$maxChar);if (($pos + ($maxChar/2)) < strlen($str)){$chunk .= '...';}break;}}- Download this code: /code/displaying_search_results_with_php2.txt
As you can see, Chunk loops through the $searchTerms array (the third argument of the constructor method) in order to see if one of the words matches a word in the given string. When it does, it saves the position of that string in the variable $pos, using PHP's built-in function strpos().
It then calculates if that position minus half the maximum amount of characters is less than zero...
if (($pos - ($maxChar/2)) < 0){$startPos = 0;}else{$startPos = ($pos - ($maxChar/2));$chunk .= '...';}- Download this code: /code/displaying_search_results_with_php3.txt
...in order to decide wether or not it should append "..." to the start of the string. The same goes for the back of the string. Using substr() it then cuts the snippet out of the string you applied as the first argument and breaks the loop.
If no match is found in the array, the class returns a snippet starting at position 0 of your string:
if ($chunk == ''){$chunk = substr($str,0,$maxChar).'...';}- Download this code: /code/displaying_search_results_with_php4.txt
Highlighting search terms
This is an important bit, you may not want this to happen in your situation, so pay attention. Since I don't want any HTML to come through, I use strip_tags() to remove every tag from the string (for extra security, you oughtta use HTMLentities() or HTMLspecialchars() on top of that).
After removing any HTML I again loop through the $searchTerms array, and replace any occurance of the words therein with a span-tag of the class "match". This way, I can highlight the words one searched for using CSS. But, if you don't want this to happen, this is the bit of code you should remove or comment out:
$chunk = strip_tags ($chunk);foreach ($searchTerms as $term){$chunk = str_replace ($term,"<span class=\"match\">$term</span>",$chunk);}- Download this code: /code/displaying_search_results_with_php5.txt
Last but not least, the get() method of the Chunk class returns the created chunk:
function get (){return $this->chunk;}- Download this code: /code/displaying_search_results_with_php6.txt
And that's it! The Chunk class can be downloaded here as a RAR-archive. From my point of view, it couldn't be any simpler, but you might think otherwise. Feel free to contact me with questions or leave a comment.
- ← previous article: Nested lists bug
- → next article: Actionscript Animation Classes
Comments:
i try your example (http://www.what...ch_results.HTML) .. but i cant see it work correctly.. :(
this comment has been quoted by Harmen Janssen
You're right, thanks very much for notifying me.
I've edited the example, it should work now.
this comment has been quoted by epul
This morning I try your example. I'm very happy it works. Great. Thanks. :)
Hello Harmen Janssen, today I try again your example. I get those results when I enter "a a" in the text field.
Results :
Lorem ipsum dolor sit an class="match">aan>met, consectetuer an class="match">aan>dipiscing elit. Aliquan class="match">aan>m vel an class="match">aan>nte an class="match">aan>c san class="match">aan>pien ultrices mollis. Proin ultrices, tellus quis sollicitudin plan class="match">aan>ceran class="match">aan>t, risus libero dan class="match">aan>pibus man class="match">aan>gnan class="match">aan>, et commodo tellus odio et sem. Etian class="match">aan>m nec leo id an class="match">aan>rcu scelerisque semper. Cran class="match">aan>s ut an class="match">aan>nte an class="match">aan> eros tristique egestan class="match">aan>s. Cran class="match">aan>s se...
Can you explain why HTML code appear on result division?.
I wonder...
Thanks again..
It's probably an error in my Javascript.
I wouldn't worry too much about it, it's only a very quick Javascript mockup. The actual PHP code should work just fine, I use it all the time in my projects :)
In the download:
if (preg_match("/$searchTerms[$i]/",$str))
reads:
if (preg_match("/$searchTems[$i]/",$str))
Nonetheless thanks