| blib/lib/Search/Circa.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % | 
| statement | 35 | 108 | 32.4 | 
| branch | 2 | 40 | 5.0 | 
| condition | 2 | 32 | 6.2 | 
| subroutine | 10 | 24 | 41.6 | 
| pod | 7 | 15 | 46.6 | 
| total | 56 | 219 | 25.5 | 
| line | stmt | bran | cond | sub | pod | time | code | 
|---|---|---|---|---|---|---|---|
| 1 | package Search::Circa; | ||||||
| 2 | |||||||
| 3 | # module Circa: provide general method for Circa | ||||||
| 4 | # Copyright 2000 A.Barbet alian@alianwebserver.com. All rights reserved. | ||||||
| 5 | # $Date: 2003/01/02 12:10:25 $ | ||||||
| 6 | |||||||
| 7 | 11 | 11 | 9908 | use DBI; | |||
| 11 | 22271 | ||||||
| 11 | 1062 | ||||||
| 8 | 11 | 11 | 19836 | use DBI::DBD; | |||
| 11 | 44232 | ||||||
| 11 | 931 | ||||||
| 9 | 11 | 11 | 7518 | use CircaConf; | |||
| 11 | 39 | ||||||
| 11 | 512 | ||||||
| 10 | 11 | 11 | 8386 | use Search::Circa::Categorie; | |||
| 11 | 40 | ||||||
| 11 | 595 | ||||||
| 11 | 11 | 11 | 9092 | use Search::Circa::Url; | |||
| 11 | 46 | ||||||
| 11 | 805 | ||||||
| 12 | 11 | 11 | 259 | use strict; | |||
| 11 | 25 | ||||||
| 11 | 538 | ||||||
| 13 | 11 | 11 | 99 | use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); | |||
| 11 | 22 | ||||||
| 11 | 1051 | ||||||
| 14 | 11 | 11 | 1728 | use Carp qw/cluck/; | |||
| 11 | 23 | ||||||
| 11 | 24244 | ||||||
| 15 | |||||||
| 16 | require Exporter; | ||||||
| 17 | |||||||
| 18 | @ISA = qw(Exporter); | ||||||
| 19 | @EXPORT = qw(); | ||||||
| 20 | $VERSION = ('$Revision: 1.18 $ ' =~ /(\d+\.\d+)/)[0]; | ||||||
| 21 | |||||||
| 22 | #------------------------------------------------------------------------------ | ||||||
| 23 | # new | ||||||
| 24 | #------------------------------------------------------------------------------ | ||||||
| 25 | sub new { | ||||||
| 26 | 1 | 1 | 0 | 3 | my $class = shift; | ||
| 27 | 1 | 5 | my $self = {}; | ||||
| 28 | 1 | 3 | bless $self, $class; | ||||
| 29 | 1 | 10 | $self->{DBH} = undef; | ||||
| 30 | 1 | 3 | $self->{PREFIX_TABLE} = 'circa_'; | ||||
| 31 | 1 | 4 | $self->{SERVER_PORT} ="3306"; # Port de mysql par default | ||||
| 32 | 1 | 3 | $self->{DEBUG} = 0; | ||||
| 33 | 1 | 4 | return $self; | ||||
| 34 | } | ||||||
| 35 | |||||||
| 36 | 0 | 0 | 0 | sub DESTROY { $_[0]->close(); } | |||
| 37 | |||||||
| 38 | |||||||
| 39 | #------------------------------------------------------------------------------ | ||||||
| 40 | # port_mysql | ||||||
| 41 | #------------------------------------------------------------------------------ | ||||||
| 42 | sub port_mysql { | ||||||
| 43 | 0 | 0 | 0 | 0 | my $self = shift; | ||
| 44 | 0 | 0 | 0 | if (@_) {$self->{SERVER_PORT}=shift;} | |||
| 0 | 0 | ||||||
| 45 | 0 | 0 | return $self->{SERVER_PORT}; | ||||
| 46 | } | ||||||
| 47 | |||||||
| 48 | #------------------------------------------------------------------------------ | ||||||
| 49 | # pre_tbl | ||||||
| 50 | #------------------------------------------------------------------------------ | ||||||
| 51 | sub pre_tbl { | ||||||
| 52 | 0 | 0 | 1 | 0 | my $self = shift; | ||
| 53 | 0 | 0 | 0 | if (@_) {$self->{PREFIX_TABLE}=shift;} | |||
| 0 | 0 | ||||||
| 54 | 0 | 0 | return $self->{PREFIX_TABLE}; | ||||
| 55 | } | ||||||
| 56 | |||||||
| 57 | #------------------------------------------------------------------------------ | ||||||
| 58 | # connect | ||||||
| 59 | #------------------------------------------------------------------------------ | ||||||
| 60 | sub connect { | ||||||
| 61 | 0 | 0 | 1 | 0 | my ($this,$user,$password,$db,$server)=@_; | ||
| 62 | 0 | 0 | 0 | 0 | if (!$user and !$password and !$db and !$server) { | ||
| 0 | |||||||
| 0 | |||||||
| 63 | 0 | 0 | 0 | $user = $this->{_USER} || $CircaConf::User; | |||
| 64 | 0 | 0 | 0 | $password = $this->{_PASSWORD} || $CircaConf::Password; | |||
| 65 | 0 | 0 | 0 | $db = $this->{_DB} || $CircaConf::Database; | |||
| 66 | 0 | 0 | 0 | $server = $this->{_HOST} || $CircaConf::Host; | |||
| 67 | } | ||||||
| 68 | 0 | 0 | 0 | $server = '127.0.0.1' if (!$server); | |||
| 69 | 0 | 0 | my $driver = "DBI:mysql:database=$db;host=$server;port=".$this->port_mysql; | ||||
| 70 | 0 | 0 | $this->{_DB}=$db; $this->{_PASSWORD}=$password; $this->{_USER}=$user; | ||||
| 0 | 0 | ||||||
| 0 | 0 | ||||||
| 71 | 0 | 0 | $this->{_HOST}=$server; | ||||
| 72 | 0 | 0 | 0 | $this->{DBH} = DBI->connect($driver,$user,$password,{ PrintError => 0 }) | |||
| 73 | || return 0; | ||||||
| 74 | 0 | 0 | return 1; | ||||
| 75 | } | ||||||
| 76 | |||||||
| 77 | #------------------------------------------------------------------------------ | ||||||
| 78 | # close | ||||||
| 79 | #------------------------------------------------------------------------------ | ||||||
| 80 | 0 | 0 | 0 | 1 | 0 | sub close {$_[0]->{DBH}->disconnect if ($_[0]->{DBH}); } | |
| 81 | |||||||
| 82 | #------------------------------------------------------------------------------ | ||||||
| 83 | # dbh | ||||||
| 84 | #------------------------------------------------------------------------------ | ||||||
| 85 | 0 | 0 | 0 | 0 | sub dbh { return $_[0]->{DBH};} | ||
| 86 | |||||||
| 87 | #------------------------------------------------------------------------------ | ||||||
| 88 | # categorie | ||||||
| 89 | #------------------------------------------------------------------------------ | ||||||
| 90 | 0 | 0 | 0 | 0 | sub categorie {return new Search::Circa::Categorie($_[0]);} | ||
| 91 | |||||||
| 92 | #------------------------------------------------------------------------------ | ||||||
| 93 | # URL | ||||||
| 94 | #------------------------------------------------------------------------------ | ||||||
| 95 | 0 | 0 | 0 | 0 | sub URL {return new Search::Circa::Url($_[0]);} | ||
| 96 | |||||||
| 97 | #------------------------------------------------------------------------------ | ||||||
| 98 | # start_classic_html | ||||||
| 99 | #------------------------------------------------------------------------------ | ||||||
| 100 | sub start_classic_html | ||||||
| 101 | { | ||||||
| 102 | 0 | 0 | 0 | 0 | my ($self,$cgi)=@_; | ||
| 103 | 0 | 0 | return $cgi->start_html | ||||
| 104 | ( -'title' => 'Circa', | ||||||
| 105 | -'author' => 'alian@alianwebserver.com', | ||||||
| 106 | -'meta' => {'keywords' => 'circa,recherche,annuaire,moteur', | ||||||
| 107 | -'copyright'=> 'copyright 1997-2000 AlianWebServer'}, | ||||||
| 108 | -'style' => {'src' => "circa.css"}, | ||||||
| 109 | -'dtd' => '-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd')."\n"; | ||||||
| 110 | } | ||||||
| 111 | |||||||
| 112 | #------------------------------------------------------------------------------ | ||||||
| 113 | # trace | ||||||
| 114 | #------------------------------------------------------------------------------ | ||||||
| 115 | sub trace { | ||||||
| 116 | 13 | 13 | 1 | 23 | my ($self, $level, $msg)=@_; | ||
| 117 | 13 | 50 | 66 | 34 | cluck if ($level >= 5 and $self->{DEBUG} >= $level); | ||
| 118 | |||||||
| 119 | 13 | 50 | 44 | if ($self->{DEBUG} >= $level) { | |||
| 120 | 0 | $msg= (' 'x(2*$level)).$msg; | |||||
| 121 | 0 | 0 | if ($msg) { | ||||
| 122 | 0 | 0 | if ($ENV{SERVER_NAME}) { | ||||
| 123 | 0 | print STDERR $msg,"\n"; } | |||||
| 124 | 0 | else { print $msg,"\n"; } | |||||
| 125 | } | ||||||
| 126 | } | ||||||
| 127 | } | ||||||
| 128 | |||||||
| 129 | #------------------------------------------------------------------------------ | ||||||
| 130 | # header | ||||||
| 131 | #------------------------------------------------------------------------------ | ||||||
| 132 | 0 | 0 | 0 | sub header {return "Content-Type: text/html\n\n";} | |||
| 133 | |||||||
| 134 | |||||||
| 135 | #------------------------------------------------------------------------------ | ||||||
| 136 | # fill_template | ||||||
| 137 | #------------------------------------------------------------------------------ | ||||||
| 138 | sub fill_template | ||||||
| 139 | { | ||||||
| 140 | 0 | 0 | 1 | my ($self,$masque,$vars)=@_; | |||
| 141 | 0 | 0 | open(FILE,$masque) || die "Can't read $masque "; | ||||
| 142 | 0 | my @buf= | |||||
| 143 | 0 | CORE::close(FILE); | |||||
| 144 | 0 | while (my ($n,$v)=each(%$vars)) | |||||
| 145 | { | ||||||
| 146 | 0 | 0 | if ($v) {map {s/<\? \$$n \?>/$v/gm} @buf;} | ||||
| 0 | |||||||
| 0 | |||||||
| 0 | |||||||
| 147 | 0 | else {map {s/<\? \$$n \?>//gm} @buf;} | |||||
| 148 | } | ||||||
| 149 | 0 | return join('',@buf); | |||||
| 150 | } | ||||||
| 151 | |||||||
| 152 | #------------------------------------------------------------------------------ | ||||||
| 153 | # fetch_first | ||||||
| 154 | #------------------------------------------------------------------------------ | ||||||
| 155 | sub fetch_first | ||||||
| 156 | { | ||||||
| 157 | 0 | 0 | 1 | my ($self,$requete)=@_; | |||
| 158 | 0 | my $sth = $self->{DBH}->prepare($requete); | |||||
| 159 | 0 | my @row; | |||||
| 160 | 0 | 0 | if ($sth->execute) { | ||||
| 161 | # Pour chaque categorie | ||||||
| 162 | 0 | @row = $sth->fetchrow_array; | |||||
| 163 | 0 | $sth->finish; | |||||
| 164 | 0 | } else { $self->trace(1,"Erreur:$requete:$DBI::errstr "); } | |||||
| 165 | 0 | 0 | if (wantarray()) { return @row; } | ||||
| 0 | |||||||
| 166 | 0 | else { return $row[0]; } | |||||
| 167 | } | ||||||
| 168 | |||||||
| 169 | #------------------------------------------------------------------------------ | ||||||
| 170 | # appartient | ||||||
| 171 | #------------------------------------------------------------------------------ | ||||||
| 172 | sub appartient | ||||||
| 173 | { | ||||||
| 174 | 0 | 0 | 0 | my ($self,$elem,@liste)=@_; | |||
| 175 | 0 | 0 | return 0 unless $elem; | ||||
| 176 | 0 | 0 | 0 | foreach (@liste) {return 1 if ($_ and $_ eq $elem);} | |||
| 0 | |||||||
| 177 | 0 | return 0; | |||||
| 178 | } | ||||||
| 179 | |||||||
| 180 | #------------------------------------------------------------------------------ | ||||||
| 181 | # prompt | ||||||
| 182 | #------------------------------------------------------------------------------ | ||||||
| 183 | sub prompt | ||||||
| 184 | { | ||||||
| 185 | 0 | 0 | 1 | my($self,$mess,$def)=@_; | |||
| 186 | 0 | 0 | my $ISA_TTY = -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT)) ; | ||||
| 187 | 0 | 0 | Carp::confess("prompt function called without an argument") | ||||
| 188 | unless defined $mess; | ||||||
| 189 | 0 | 0 | my $dispdef = defined $def ? "[$def] " : " "; | ||||
| 190 | 0 | 0 | $def = defined $def ? $def : ""; | ||||
| 191 | 0 | my $ans; | |||||
| 192 | 0 | local $|=1; | |||||
| 193 | 0 | print "$mess $dispdef"; | |||||
| 194 | 0 | 0 | if ($ISA_TTY) { chomp($ans = | ||||
| 0 | |||||||
| 195 | 0 | else { print "$def\n"; } | |||||
| 196 | 0 | 0 | return ($ans ne '') ? $ans : $def; | ||||
| 197 | } | ||||||
| 198 | |||||||
| 199 | #------------------------------------------------------------------------------ | ||||||
| 200 | # POD DOCUMENTATION | ||||||
| 201 | #------------------------------------------------------------------------------ | ||||||
| 202 | |||||||
| 203 | =head1 NAME | ||||||
| 204 | |||||||
| 205 | Search::Circa - a Search Engine / Indexer running with Mysql | ||||||
| 206 | |||||||
| 207 | =head1 DESCRIPTION | ||||||
| 208 | |||||||
| 209 | This is Search::Circa, a module who provide functions to | ||||||
| 210 | perform search on Circa, a www search engine running with | ||||||
| 211 | Mysql. Circa is for your Web site, or for a list of sites. | ||||||
| 212 | It indexes like Altavista does. It can read, add and | ||||||
| 213 | parse all url's found in a page. It add url and word | ||||||
| 214 | to MySQL for use it at search. | ||||||
| 215 | |||||||
| 216 | Circa can be used for index 100 to 100 000 url | ||||||
| 217 | |||||||
| 218 | Notes: | ||||||
| 219 | |||||||
| 220 | =over | ||||||
| 221 | |||||||
| 222 | =item * | ||||||
| 223 | |||||||
| 224 | Accents are removed on search and when indexed | ||||||
| 225 | |||||||
| 226 | =item * | ||||||
| 227 | |||||||
| 228 | Search are case unsensitive (mmmh what my english ? ;-) | ||||||
| 229 | |||||||
| 230 | =back | ||||||
| 231 | |||||||
| 232 | Search::Circa::Search work with Search::Circa::Indexer result. | ||||||
| 233 | Search::Circa::Search is a Perl interface, but it's exist on | ||||||
| 234 | this package a PHP client too. | ||||||
| 235 | |||||||
| 236 | Search::Circa is root class for Search::Circa::Indexer and | ||||||
| 237 | Search::Circa::Search. | ||||||
| 238 | |||||||
| 239 | =head1 SYNOPSIS | ||||||
| 240 | |||||||
| 241 | See L | ||||||
| 242 | |||||||
| 243 | =head1 FEATURES | ||||||
| 244 | |||||||
| 245 | =over | ||||||
| 246 | |||||||
| 247 | =item * | ||||||
| 248 | |||||||
| 249 | Search Features | ||||||
| 250 | |||||||
| 251 | =over | ||||||
| 252 | |||||||
| 253 | =item * | ||||||
| 254 | |||||||
| 255 | Boolean query language support : or (default) and ("+") not ("-"). Ex perl + faq -cgi : | ||||||
| 256 | Documents with faq, eventually perl and not cgi. | ||||||
| 257 | |||||||
| 258 | =item * | ||||||
| 259 | |||||||
| 260 | Client Perl or PHP | ||||||
| 261 | |||||||
| 262 | =item * | ||||||
| 263 | |||||||
| 264 | Can browse site by directory / rubrique. | ||||||
| 265 | |||||||
| 266 | =item * | ||||||
| 267 | |||||||
| 268 | Search for different criteria: news, last modified date, language, URL / site. | ||||||
| 269 | |||||||
| 270 | =back | ||||||
| 271 | |||||||
| 272 | =item * | ||||||
| 273 | |||||||
| 274 | Full text indexing | ||||||
| 275 | |||||||
| 276 | =item * | ||||||
| 277 | |||||||
| 278 | Different weights for title, keywords, description and rest of page HTML read can be given in configuration | ||||||
| 279 | |||||||
| 280 | =item * | ||||||
| 281 | |||||||
| 282 | Herite from features of LWP suite: | ||||||
| 283 | |||||||
| 284 | =over | ||||||
| 285 | |||||||
| 286 | =item * | ||||||
| 287 | |||||||
| 288 | Support protocol HTTP://,FTP://, FILE:// (Can do indexation of filesystem without talk to Web Server) | ||||||
| 289 | |||||||
| 290 | =item * | ||||||
| 291 | |||||||
| 292 | Full support of standard robots exclusion (robots.txt). Identification with | ||||||
| 293 | CircaIndexer/0.1, mail alian@alianwebserver.com. Delay requests to | ||||||
| 294 | the same server for 8 secondes. "It's not a bug, it's a feature!" Basic | ||||||
| 295 | rule for HTTP serveur load. | ||||||
| 296 | |||||||
| 297 | =item * | ||||||
| 298 | |||||||
| 299 | Support proxy HTTP. | ||||||
| 300 | |||||||
| 301 | =back | ||||||
| 302 | |||||||
| 303 | =item * | ||||||
| 304 | |||||||
| 305 | Make index in MySQL | ||||||
| 306 | |||||||
| 307 | =item * | ||||||
| 308 | |||||||
| 309 | Read HTML and full text plain | ||||||
| 310 | |||||||
| 311 | =item * | ||||||
| 312 | |||||||
| 313 | Several kinds of indexing : full, incremental, only on a particular server. | ||||||
| 314 | |||||||
| 315 | =item * | ||||||
| 316 | |||||||
| 317 | Documents not updated are not reindexed. | ||||||
| 318 | |||||||
| 319 | =item * | ||||||
| 320 | |||||||
| 321 | All requests for a file are made first with a head http request, for information | ||||||
| 322 | such as validate, last update, size, etc.Size of documents read can be | ||||||
| 323 | restricted (Ex: don't get all documents > 5 MB). For use with low-bandwidth | ||||||
| 324 | connections, or computers which do not have much memory. | ||||||
| 325 | |||||||
| 326 | =item * | ||||||
| 327 | |||||||
| 328 | HTML template can be easily customized for your needs. | ||||||
| 329 | |||||||
| 330 | =item * | ||||||
| 331 | |||||||
| 332 | Admin functions available by browser interface or command-line. | ||||||
| 333 | |||||||
| 334 | =item * | ||||||
| 335 | |||||||
| 336 | Index the different links found in a CGI (all after name_of_file?) | ||||||
| 337 | |||||||
| 338 | =back | ||||||
| 339 | |||||||
| 340 | =head1 FREQUENTLY ASKED QUESTIONS | ||||||
| 341 | |||||||
| 342 | Q: Where are clients for example ? | ||||||
| 343 | |||||||
| 344 | A: See in demo directory. For command line, see circa_admin and circa_search,, | ||||||
| 345 | for CGI, take a look in cgi-bin/circa, they are installed with make cgi. | ||||||
| 346 | |||||||
| 347 | Q: Where are global parameters to connect to Circa ? | ||||||
| 348 | |||||||
| 349 | A: Use lib/CircaConf.pm file | ||||||
| 350 | |||||||
| 351 | Q : What is an account for Circa ? | ||||||
| 352 | |||||||
| 353 | A: It's like a project, or a databse. A namespace for what you want. | ||||||
| 354 | |||||||
| 355 | Q : How I begin with indexer ? | ||||||
| 356 | |||||||
| 357 | A: See man page of L | ||||||
| 358 | |||||||
| 359 | Q : Did you succed to use Circa with mod_perl ? | ||||||
| 360 | |||||||
| 361 | A: Yes | ||||||
| 362 | |||||||
| 363 | =head1 Public interface | ||||||
| 364 | |||||||
| 365 | You use this method behind Search::Circa::Indexer and | ||||||
| 366 | Search::Circa::Search object | ||||||
| 367 | |||||||
| 368 | =over | ||||||
| 369 | |||||||
| 370 | =item B | ||||||
| 371 | |||||||
| 372 | Connect Circa to MySQL. Return 1 on succes, 0 else | ||||||
| 373 | |||||||
| 374 | =over | ||||||
| 375 | |||||||
| 376 | =item * | ||||||
| 377 | |||||||
| 378 | user : Utilisateur MySQL | ||||||
| 379 | |||||||
| 380 | =item * | ||||||
| 381 | |||||||
| 382 | password : Mot de passe MySQL | ||||||
| 383 | |||||||
| 384 | =item * | ||||||
| 385 | |||||||
| 386 | db : Database MySQL | ||||||
| 387 | |||||||
| 388 | =item * | ||||||
| 389 | |||||||
| 390 | bost : Adr IP du serveur MySQL | ||||||
| 391 | |||||||
| 392 | =back | ||||||
| 393 | |||||||
| 394 | Connect Circa to MySQL. Return 1 on succes, 0 else | ||||||
| 395 | |||||||
| 396 | =item B | ||||||
| 397 | |||||||
| 398 | Close connection to MySQL. This method is called with DESTROY method of this | ||||||
| 399 | class. | ||||||
| 400 | |||||||
| 401 | =item B | ||||||
| 402 | |||||||
| 403 | Get or set the prefix for table name for use Circa with more than one | ||||||
| 404 | time on a same database | ||||||
| 405 | |||||||
| 406 | =item B | ||||||
| 407 | |||||||
| 408 | =over | ||||||
| 409 | |||||||
| 410 | =item * | ||||||
| 411 | |||||||
| 412 | masque : Path of template | ||||||
| 413 | |||||||
| 414 | =item * | ||||||
| 415 | |||||||
| 416 | vars : hash ref with keys/val to substitue | ||||||
| 417 | |||||||
| 418 | =back | ||||||
| 419 | |||||||
| 420 | Give template with remplaced variables | ||||||
| 421 | Ex: | ||||||
| 422 | |||||||
| 423 | $circa->fill_template('A $age ?> ans', ('age' => '12 ans')); | ||||||
| 424 | |||||||
| 425 | Will return: | ||||||
| 426 | |||||||
| 427 | J'ai 12 ans, | ||||||
| 428 | |||||||
| 429 | =item B | ||||||
| 430 | |||||||
| 431 | Execute request SQL on db and return first row. In list context, retun full | ||||||
| 432 | row, else return just first column. | ||||||
| 433 | |||||||
| 434 | =item B | ||||||
| 435 | |||||||
| 436 | Print message I | ||||||
| 437 | is upper than I | ||||||
| 438 | |||||||
| 439 | =item B | ||||||
| 440 | |||||||
| 441 | Ask in STDIN for a parameter with message and default_value and return value | ||||||
| 442 | |||||||
| 443 | =back | ||||||
| 444 | |||||||
| 445 | =head1 SEE ALSO | ||||||
| 446 | |||||||
| 447 | L | ||||||
| 448 | |||||||
| 449 | L | ||||||
| 450 | |||||||
| 451 | L | ||||||
| 452 | |||||||
| 453 | L | ||||||
| 454 | |||||||
| 455 | L | ||||||
| 456 | |||||||
| 457 | =head1 VERSION | ||||||
| 458 | |||||||
| 459 | $Revision: 1.18 $ | ||||||
| 460 | |||||||
| 461 | =head1 AUTHOR | ||||||
| 462 | |||||||
| 463 | Alain BARBET alian@alianwebserver.com | ||||||
| 464 | |||||||
| 465 | =cut | ||||||
| 466 | |||||||
| 467 | 1; |