#!/usr/bin/perl # ------------- # Links # ------------- # Links Manager # # File: search.cgi # Description: Searches the database and produces a list of results. If no options are # given, the script will produce a search form found in site_html.pl. # Author: Alex Krohn # Email: alex@gossamer-threads.com # Web: http://www.gossamer-threads.com/ # Version: 2.01 # # (c) 1998 Gossamer Threads Inc. # # This script is not freeware! Please read the README for full details # on registration and terms of use. # ===================================================================== # # Form Input: # 'type' : can be either 'keyword' or 'phrase'. # 'bool' : can be either 'and' or 'or'. # 'mh' : the maximum number of hits, can be either 10, 25, 50, 100. # 'nh' : the page hit we are on. # # Setup: # Make sure the require statement below points to the config file. # Required Librariers # -------------------------------------------------------- eval { ($0 =~ m,(.*)/[^/]+,) && unshift (@INC, "$1"); # Get the script location: UNIX / ($0 =~ m,(.*)\\[^\\]+,) && unshift (@INC, "$1"); # Get the script location: Windows \ require "admin/links.cfg"; # Change this to full path to links.cfg if you have problems. require "$db_lib_path/db_utils.pl"; require "$db_lib_path/links.def"; $build_use_templates ? require "$db_lib_path/site_html_templates.pl" : require "$db_lib_path/site_html.pl"; }; if ($@) { print "Content-type: text/plain\n\n"; print "Error including libraries: $@\n"; print "Make sure they exist, permissions are set properly, and paths are set correctly."; exit; } # ======================================================== eval { &main; }; # Trap any fatal errors so the program hopefully if ($@) { &cgierr("fatal error: $@"); } # never produces that nasty 500 server error page. exit; # There are only two exit calls in the script, here and in in &cgierr. sub main { # -------------------------------------------------------- %in = &parse_form(); # Display the form if called with no input. (keys %in <= 0) and &site_html_search_form() and return; # Set maximum hits -- default to 25. local $maxhits = 2375; if ($in{'mh'} && (($in{'mh'} == 10) || ($in{'mh'} == 25) || ($in{'mh'} == 50) || ($in{'mh'} = 100))) { $maxhits = $in{'mh'}; } # Set search type -- either phrase or keyword. Also build keyword list to search on. my @search_terms = (); ($in{'type'} eq 'phrase') ? (@search_terms = ($in{'query'})) : (@search_terms = split (/\s/, $in{'query'})); # Set boolean connector and next hits page. my $bool = $in{'bool'} || 'and'; my $nh = $in{'nh'} || 1; # Store the search results here. local (%link_results, @category_results); # Do the actual search. my $status = &search (\@search_terms, $bool); if ($status ne "ok") { &site_html_search_failure ($status); return; } # Return unless we have results. ((keys %link_results > 0) or ($#category_results >= 0)) or &site_html_search_failure ("no matching records") and return; # The HTML used in the output is stored here. local ($cat_hits, $link_hits, $category_results, $link_results, $next); # Build the HTML for the category results and store it in "$category_results". Only build the html # if we are on the first set of link results. foreach $category (@category_results) { if ($nh == 1) { $cat_clean = &build_clean($category); $linked_title = &build_linked_title ($category); # $category_results .= qq|
$title_linked\n|;
$link_results .= $link_output{$setoflinks};
}
# If we want to bold the search terms...
if ($search_bold) {
foreach $term (@search_terms) {
# This reg expression will do the trick, and doesn't bold things inside <> tags such as
# URL's.
$link_results =~ s,(<[^>]+>)|(\Q$term\E),defined($1) ? $1 : "$2",gie;
$category_results =~ s,(<[^>]+>)|(\Q$term\E),defined($1) ? $1 : "$2",gie;
}
}
# If we have to many hits, let's build the next toolbar, and return only the hits we want.
my ($next_hit, $prev_hit, $next_url, $left, $right, $lower, $upper, $i);
if ($link_hits > $maxhits) {
# Remove the nh= from the query string.
$next_url = $ENV{'QUERY_STRING'};
$next_url =~ s/\&nh=\d+//;
$next_hit = $nh + 1; $prev_hit = $nh - 1;
# Build the next hits toolbar. It seems really complicated as we have to do
# some number crunching to keep track of where we are on the toolbar, and so
# that the toolbar stays centred.
# First, set how many pages we have on the left and the right.
$left = $nh; $right = int($numhits/$maxhits) - $nh;
# Then work out what page number we can go above and below.
($left > 7) ? ($lower = $left - 7) : ($lower = 1);
($right > 7) ? ($upper = $nh + 7) : ($upper = int($link_hits/$maxhits) + 1);
# Finally, adjust those page numbers if we are near an endpoint.
(7 - $nh >= 0) and ($upper = $upper + (8 - $nh));
($nh > ($link_hits/$maxhits - 7)) and ($lower = $lower - ($nh - int($link_hits/$maxhits - 7) - 1));
$next = "";
# Then let's go through the pages and build the HTML.
($nh > 1) and ($next .= qq~[<<] ~);
for ($i = 1; $i <= int($link_hits/$maxhits) + 1; $i++) {
if ($i < $lower) { $next .= " ... "; $i = ($lower-1); next; }
if ($i > $upper) { $next .= " ... "; last; }
($i == $nh) ?
($next .= qq~$i ~) :
($next .= qq~$i ~);
(($i * $maxhits) >= $link_hits) and last; # Special case if we hit exact.
}
$next .= qq~[>>] ~ unless ($nh == $i);
}
# Print out the HTML results.
&site_html_search_results;
}
sub search {
# --------------------------------------------------------
# This routine does the actual search of the database.
#
my ($search_terms, $bool) = @_;
my ($regexp, @values, $grand_total, $match, $andmatch, $field, $or_match, %seen, $link, $tmp);
# Save the reg expressions to avoid rebuilding.
$or_match = $bool ne 'and';
if ($or_match) {
for (0 .. $#{$search_terms}) {
next if (length ${$search_terms}[$_] < 2); # Skip single letter words.
$tmp .= "m/\Q${$search_terms}[$_]\E/io ||";
}
}
else {
for (0 .. $#{$search_terms}) {
next if (length ${$search_terms}[$_] < 2); # Skip single letter words.
$tmp .= "m/\Q${$search_terms}[$_]\E/io &&";
}
}
chop ($tmp); chop ($tmp);
# We can also search by field names.
my @field_search;
for (0 .. $#db_cols) {
exists $in{$db_cols[$_]} and (push (@field_search, $_));
}
if (!$tmp and !@field_search) { return ("Please enter one or more keywords."); }
if ($tmp) { $regexp = eval "sub { $tmp }"; $@ and &cgierr ("Can't compile reg exp: $tmp! Reason: $@");}
# Go through the database.
open (DB, "<$db_file_name") or &cgierr("error in search. unable to open database: $db_file_name. Reason: $!");
flock (DB, 1) if ($db_use_flock);
LINE: while (