Login

Search This!

Add search capabilities to your site using the popular open source tools PHP3 and ht://Dig.So, you want to put a “Search This Site” button on your PHP3 sites? Well, unless
all your pages are stored in a database (ugh!), there is no easy way to do this
using PHP alone.

The solution is to use another program designed specifically for indexing and
searching your site, and then use the results of that program in your PHP
script.

When I first needed this functionality for a site I was designing for the
SummerWorks Theatre Festival, I came across ht://Dig. For those who don’t know,
“The ht://Dig system is a complete world wide web indexing and searching system
for a small domain or intranet. … [It] is meant to cover the search needs for
a single company, campus, or even a particular sub section of a web site.”

This tutorial will cover the following steps needed to get these two great
Open Source applications working together:

Installing ht://Dig

Configuring ht://Dig

Indexing the Site

Building the Search Page

Performing the Search

Parsing and Displaying the Results

Installing ht://Dig

I’m not going to spend much time on this section, since the ht://Dig
documentation can answer any questions much better than I can in this tutorial.

As of this writing, the latest version of ht://Dig is 3.1.0b4. The latest
version can always be found at http://www.htdig.org.

Once you’ve downloaded the archive, and unzipped it, read the README and htdocs/install.html files for the latest
information and instructions on how to install. I’m running Linux 2.0.35 and
Apache 1.3.3, so your set-up may vary, but the first step is to run the
configuration program.

% ./configure

You may then want to edit the CONFIG file. Specifically I changed
these four settings to the following values:

The last two settings aren’t too important, because we’re going to be making
our own search script and interface using PHP3.

Once the CONFIG file is to your liking, run make and then make
install:

% make
% make install

If all went well, ht://Dig should be installed and we can move on to
configuring it to work with PHP.

{mospagebreak title=Configuring ht://Dig}
Before going any further, it would help if you have a clear idea of how ht://Dig
works. There is a very nice explanation on the ht://Dig website (follow the link
to “How it Works” on the left side), but here’s the abridged version.

The ht://Dig system performs three major tasks that should be performed in
the following order:

Digging

Before you can search, a database of all the documents that need to be
searched has to be created.

Merging

Once the document database has been created, it has to be converted to
something that can be searched quickly. Also, if you want to only update changed
documents, these changes have to be merged into the searchable database.

Even though this task could be performed at the same time as digging, it is a
separate process for efficiency reasons. It also gives more flexibility to what
actually happens at merge time.

Searching

Finally, the databases that were created in the previous steps can be used to
perform actual searches. Normally, searches will be invoked by a CGI program
which gets its input from the user through an HTML form … but we’ll be doing
it all with PHP3!

So, let’s see what the installation created, shall we?

% cd /usr/local/htdig/
% ls
bin common conf db

The bin/ directory contains the executables required by
ht://Dig. Configurations files are in conf/ (believe it or not!)
and I think you can guess where the database files are.

[Note: I’m going to assume from now on the you installed ht://Dig in the /usr/local/htdig directory as shown above, and that the path to
your website files is /www, probably a symlink to /usr/local/htdocs.]

If your web server is like mine, you’re probably running several web sites
off the same machine. In this case, I’ve found it useful to have separate
configuration files for each site. ht://Dig installed a sample configuration
file called htdig.conf, so I recommend you copy it to a new
filename and make some changes. Here is the sw98.conf file I used
for the SummerWorks Theatre Festival’s website:

What do all these settings mean? Some are obvious, but the following probably
are not:

database_dir:Normally all database files are in the /usr/local/htdig/db/ directory. To keep things a bit cleaner, I’ve
made sub-directories for all the sites on my server, so this is the
sub-directory for the SummerWorks site. You’ll need to make this directory
manually before you can index the site:

% cd /usr/local/htdig/db
% mkdir sw98

exclude_urls:There are some files we don’t want to search. If a
URL contains any of the space separated patterns, it will not be indexed. In
this case, I didn’t want the staff pages, nor the search pages indexed. I also
wanted it to ignore .inc files (common PHP code that I include on
various pages), and some Word documents for PC and Mac. On the real SummerWorks
site, there are a couple more exclusions, but you get the idea (I hope!).

search_algorithm:ht://Dig lets you turn “fuzzy” searching on or
off. When it’s on, people who search for “play”, for example, will also find
things like “plays”, “player”, “players”, etc.. This slows down the digging
process a fair amount, but can be useful. The different weights applied to each
algorithm mean, in this case, that a search for “play” will turn up “player”,
but not as high in the results as an exact match for “play”.

template_map:This makes a new template called “sw98”. More on
templates below.

search_results_header, search_results_footer, nothing_found_file, and syntax_error_file:These are files used
by the template, and parsed by PHP. More below.

max_doc_size:This is bigger than usual, since there are some big
pages on the site. If you find that some of your pages aren’t being indexed,
setting this to a higher value will often solve the problem.

valid_punctuation:I basically only added the French quotes and the
single quote to the list of valid punctuation. This is the set of characters
which will be deleted from the document before determining what a word is. This
means that if a document contains something like “Andrew’s” the digger will see
this as “Andrews”.

The same transformation is performed on the keywords sent to the search
engine.

There are plenty of other setting you can set in the .conf file.
For a definitive list with explanations, check out the ht://Dig website.

Templates

ht://Dig makes extensive use of templates for it’s output. These templates
are (usually) plain HTML documents containing variables, which are substituted
with the search results.

There are four “standard” template setting in the .conf file:

search_results_header:This specifies a filename to be output at
the start of search results.

search_results_footer:This specifies a filename to be output at
the end of search results.

nothing_found_file:This specifies the file which contains the text
to display when no matches were found.

syntax_error_file:This points to the file which will be displayed
if a boolean expression syntax error was found.

There is also the result template file. This is the file referenced in the template_map attribute of the .conf file. This is where all
the information you want the search to return is displayed.

I said that these templates usually contain a bunch of HTML, with some
variable substitution. When using ht://Dig with PHP, it would be much easier if
a search returned the raw results of the search. You can then use PHP to parse
and display that information however you want.

The easiest way to do this is to not put any HTML in the template files, but
instead just put in the list of variables you want substituted.

So, make your results-header.html file contain only the
following 4 lines:

$(MATCHES)
$(FIRSTDISPLAYED)
$(LASTDISPLAYED)
$(LOGICAL_WORDS)

results-nomatch.html should contain only 1 line (note that it’s
not a variable):

NOMATCH

results-template.html consists of 4 lines:

$(TITLE)
$(URL)
$(PERCENT)
$(EXCERPT)

Finally, results-syntaxerror.html consists of 2 lines:

SYNTAXERROR
$(SYNTAXERROR)

It’s important that there be no extra line breaks at the beginning or end of
your files, since we’re going to rely on the fact that every fourth line of the results-template.html file (for instance) is the title of the
document.

All of the template files are in a sub-directory of the website called search/.

If you want to find out what all the variables mean (and what other ones are
available), check the ht://Dig site.

{mospagebreak title=Indexing the Site}
Before ht://Dig can search your site, it has to index it.

ht://Dig retrieves HTML documents using the HTTP protocol and gathers
information from these documents which can later be used to search them. In this
way, it works very much like a search robot or web spider.

[Note: ht://Dig can also operate locally, indexing a site through the local
file system. While this is a faster way of indexing a site, it doesn’t work very
well when indexing dynamic pages. Why? Well, it would indexing the source of a PHP file, not the result. And that’s not what you want.]

Every time you make a change to your site, you’ll want to re-index it. So
it’s probably a good idea to write a little shell script that indexes your site
for you, and add it to your crontab. Here is rundig.sh, a script
that does just that for the SummerWorks site, and emails me the details. The
changes you need to make for your site should be obvious.

Run this from the command line with the -v switch and you can watch as your
site is indexed! You’ll need to run this as root (or the same user you installed
ht://Dig as) so that it can create the necessary files in /usr/local/htdig/db.

{mospagebreak title=Building the Search Page} Now that your site is being indexed regularly (you did put an entry for rundig.sh in your crontab, right?), you can search the site.

{mospagebreak title=Performing the Search} ht://Dig is
normally run as a CGI script (“normally” meaning “by everyone who doesn’t use
PHP3!”). To run the search program from PHP, you will need a file called htdig.sh which looks like this:

$HTSEARCH_PROG is the location of the htdig.sh program. $search is passed from the form, and
is the list of words to search for. $config tells ht://Dig which .conf file to use, and $format tells it which template
map to use from the .conf file.

Then we run the search:

<?
$command=”$HTSEARCH_PROG “$query””;
exec($command,$result);
?>

This puts the results of the search into the array $result, which
PHP then parses to display the results.

{mospagebreak title=Displaying the Results}

This is where ht://Dig’s templates are put to work. First, let’s count the
number of lines returned by the search:

<?php
$rc = count($result);
?>

The first two lines are always going to be the HTTP header

Content-type: text/html n
n

so we can skip them (remember, ht://Dig was designed to output HTML).

If the search produced an error, we’d get no results or a one-line error, so:

Let’s also check to see that we got some matches. If we didn’t, then ht://Dig
will just echo out the two-line HTTP header, then the contents of the results-nomatch.html file. We use that information to perform the
check:

<?php
elseif ($result[2]==”NOMATCH”):
echo “There were no matches for <B>$search</B> found on the website.<P>n”;
?>

We know to look for “NOMATCH” because that’s the string in
results-nomatch.html).

I’m echoing out the variable words here, instead of $search. That’s because if I have fuzzy searching turned on and I
search for “play”, then $search will equal “play”, but $words will equal “(play or played or playing or player or plays or
players)” … which what you are really searching for.

There are a few quirks to keep in mind. Notably, ht://Dig outputs an
additional new-line after the $(STARSLEFT) and $(STARSRIGHT) variables in the
template. You need to keep this in mind when figuring out which line of $result corresponds to what piece of information. For example, if I
changed $(PERCENT) to $(STARSLEFT) in my .conf file, I would need
to make the following changes to the code:

But the basic strategy is always the same: PHP loops through the array $result and outputs the information. If you want to see the contents
of $result for yourself (to make sure you’re getting the right
results), just replace the entire last else- block above with:

<?php
while (list($k,$v)=each($result)) {
echo “$k -> $v n”;
}
?>

Conclusion and Advanced Topics

You should all be running out now and adding “Search this Site” buttons to
your PHP-driven web pages. This tutorial covered the basics, but there are a lot
of advanced things you can do with ht://Dig and PHP:

show matches in groups (e.g. “Matches 1-10”, “Matches 11-20”)

“fix” the URL for matches for sites that are in framesets

index and search not only HTML and PHP pages, but also PDF (Acrobat) and
Microsoft Word documents using external parsers