00001 <?php
00002
# See search.doc
00003
00004 class SearchEngine {
00005 var
$mUsertext,
$mSearchterms;
00006 var
$mTitlecond,
$mTextcond;
00007
00008 var
$doSearchRedirects =
true;
00009 var
$addtoquery = array();
00010 var
$namespacesToSearch = array();
00011 var
$alternateTitle;
00012 var
$all_titles =
false;
00013
00014 function
SearchEngine( $text )
00015 {
00016
# We display the query, so let's strip it for safety
00017
#
00018
global
$wgDBmysql4;
00019
$lc =
SearchEngine::legalSearchChars() .
"()";
00020
if(
$wgDBmysql4 )
$lc .=
"\"~<>*+-";
00021 $this->mUsertext = trim( preg_replace(
"/[^{$lc}]/",
" ", $text ) );
00022 $this->
mSearchterms = array();
00023 $this->mStrictMatching =
true; # Google-style, add
'+' on all terms
00024 }
00025
00026 function
queryNamespaces()
00027 {
00028
$namespaces = implode(
",", $this->namespacesToSearch );
00029
if (
$namespaces ==
"") {
00030
$namespaces =
"0";
00031 }
00032
return "AND cur_namespace IN (" .
$namespaces .
")";
00033 }
00034
00035 function
searchRedirects()
00036 {
00037
if ( $this->doSearchRedirects ) {
00038
return "";
00039 }
else {
00040
return "AND cur_is_redirect=0 ";
00041 }
00042 }
00043
00044 function
initNamespaceCheckbox( $i )
00045 {
00046 global
$wgUser,
$wgNamespacesToBeSearchedDefault;
00047
00048
if (
$wgUser->getID()) {
00049
00050
return $wgUser->getOption(
"searchNs".$i );
00051 }
else {
00052
00053
return !empty($wgNamespacesToBeSearchedDefault[ $i ]);
00054 }
00055 }
00056
00057
# Display the "power search" footer. Does not actually perform the search,
00058
# that is done by showResults()
00059 function
powersearch()
00060 {
00061 global
$wgUser,
$wgOut,
$wgLang,
$wgTitle,
$wgRequest;
00062 $sk =&
$wgUser->getSkin();
00063
00064 $search =
$wgRequest->getText( 'search' );
00065 $searchx =
$wgRequest->getVal( 'searchx' );
00066 $listredirs =
$wgRequest->getVal( 'redirs' );
00067
00068 $ret =
wfMsg(
"powersearchtext"); # Text to be returned
00069 $tempText =
""; # Temporary text,
for substitution into $ret
00070
00071
if( isset( $_REQUEST[
"searchx"] ) ) {
00072 $this->addtoquery[
"searchx"] =
"1";
00073 }
00074
00075
# Do namespace checkboxes
00076
$namespaces =
$wgLang->getNamespaces();
00077 foreach ( $namespaces as $i => $
namespace ) {
00078
# Skip virtual namespaces
00079
if (
$i < 0 ) {
00080
continue;
00081 }
00082
00083 $formVar =
"ns$i";
00084
00085
# Initialise checkboxValues, either from defaults or from
00086
# a previous invocation
00087
if ( !isset( $searchx ) ) {
00088 $checkboxValue = $this->initNamespaceCheckbox( $i );
00089 }
else {
00090 $checkboxValue =
$wgRequest->getVal( $formVar );
00091 }
00092
00093 $checked =
"";
00094
if ( $checkboxValue == 1 ) {
00095 $checked =
" checked='checked'";
00096 $this->addtoquery[
"ns{$i}"] = 1;
00097 array_push( $this->namespacesToSearch, $i );
00098 }
00099 $name = str_replace(
"_",
" ", $namespaces[$i] );
00100
if (
"" == $name ) {
00101 $name =
wfMsg(
"blanknamespace" );
00102 }
00103
00104
if ( $tempText !==
"" ) {
00105 $tempText .=
" ";
00106 }
00107 $tempText .=
"<input type='checkbox' value=\"1\" name=\"" .
00108
"ns{$i}\"{$checked} />{$name}\n";
00109 }
00110 $ret = str_replace (
"$1", $tempText, $ret );
00111
00112
# List redirects checkbox
00113
00114 $checked =
"";
00115
if ( $listredirs == 1 ) {
00116 $this->addtoquery[
"redirs"] = 1;
00117 $checked =
" checked='checked'";
00118 }
00119 $tempText =
"<input type='checkbox' value='1' name=\"redirs\"{$checked} />\n";
00120 $ret = str_replace(
"$2", $tempText, $ret );
00121
00122
# Search field
00123
00124 $tempText =
"<input type='text' name=\"search\" value=\"" .
00125 htmlspecialchars( $search ) .
"\" width='80' />\n";
00126 $ret = str_replace(
"$3", $tempText, $ret );
00127
00128
# Searchx button
00129
00130 $tempText =
"<input type='submit' name=\"searchx\" value=\"" .
00131
wfMsg(
"powersearch") .
"\" />\n";
00132 $ret = str_replace(
"$9", $tempText, $ret );
00133
00134
$action = $sk->escapeSearchLink();
00135 $ret =
"<br /><br />\n<form id=\"powersearch\" method=\"get\" " .
00136
"action=\"$action\">\n{$ret}\n</form>\n";
00137
00138
if ( isset ( $searchx ) ) {
00139
if ( ! $listredirs ) {
00140 $this->doSearchRedirects =
false;
00141 }
00142 }
00143
return $ret;
00144 }
00145
00146 function
setupPage() {
00147 global
$wgOut;
00148
$wgOut->setPageTitle(
wfMsg(
"searchresults" ) );
00149 $q =
wfMsg(
"searchquery", htmlspecialchars( $this->mUsertext ) );
00150
$wgOut->setSubtitle( $q );
00151
$wgOut->setArticleRelated(
false );
00152
$wgOut->setRobotpolicy(
"noindex,nofollow" );
00153 }
00154
00155
# Perform the search and construct the results page
00156 function
showResults()
00157 {
00158 global
$wgUser,
$wgTitle,
$wgOut,
$wgLang,
$wgRequest;
00159 global
$wgDisableTextSearch,
$wgInputEncoding;
00160 $fname =
"SearchEngine::showResults";
00161
00162 $search =
$wgRequest->getText( 'search' );
00163
00164 $powersearch = $this->
powersearch();
00165
00166 $this->
setupPage();
00167
00168 $sk =
$wgUser->getSkin();
00169 $header =
wfMsg(
"searchresulttext", $sk->makeKnownLink(
00170
wfMsg(
"searchhelppage" ),
wfMsg(
"searchingwikipedia" ) ) );
00171
$wgOut->addHTML( $header );
00172
00173 $this->
parseQuery();
00174
if (
"" == $this->
mTitlecond ||
"" == $this->
mTextcond ) {
00175
$wgOut->addHTML(
"<h2>" .
wfMsg(
"badquery" ) .
"</h2>\n" .
00176
"<p>" .
wfMsg(
"badquerytext" ) .
"</p>\n" );
00177
return;
00178 }
00179 list( $limit, $offset ) =
wfCheckLimits( 20,
"searchlimit" );
00180
00181 $searchnamespaces = $this->
queryNamespaces();
00182 $redircond = $this->
searchRedirects();
00183
00184
if (
$wgDisableTextSearch ) {
00185
$wgOut->addHTML(
wfMsg(
"searchdisabled" ) );
00186
$wgOut->addHTML(
wfMsg(
"googlesearch", htmlspecialchars( $search ), $GLOBALS['wgInputEncoding'] ) );
00187 }
else {
00188
$sql =
"SELECT cur_id,cur_namespace,cur_title," .
00189
"cur_text FROM cur,searchindex " .
00190
"WHERE cur_id=si_page AND {$this->mTitlecond} " .
00191
"{$searchnamespaces} {$redircond}" .
00192
"LIMIT {$offset}, {$limit}";
00193 $res1 =
wfQuery( $sql,
DB_READ, $fname );
00194 $num =
wfNumRows($res1);
00195
00196 $sk =
$wgUser->getSkin();
00197 $text =
"";
00198
00199 $this->
parseQuery();
00200
if (
"" == $this->
mTitlecond ||
"" == $this->
mTextcond ) {
00201
$wgOut->addHTML(
"<h2>" .
wfMsg(
"badquery" ) .
"</h2>\n" .
00202
"<p>" .
wfMsg(
"badquerytext" ) .
"</p>\n" );
00203
return;
00204 }
00205 list( $limit, $offset ) =
wfCheckLimits( 20,
"searchlimit" );
00206
00207 $searchnamespaces = $this->
queryNamespaces();
00208 $redircond = $this->
searchRedirects();
00209
00210
$sql =
"SELECT cur_id,cur_namespace,cur_title," .
00211
"cur_text FROM cur,searchindex " .
00212
"WHERE cur_id=si_page AND {$this->mTitlecond} " .
00213
"{$searchnamespaces} {$redircond}" .
00214
"LIMIT {$offset}, {$limit}";
00215 $res1 =
wfQuery( $sql,
DB_READ, $fname );
00216 $num =
wfNumRows($res1);
00217
00218
$sql =
"SELECT cur_id,cur_namespace,cur_title," .
00219
"cur_text FROM cur,searchindex " .
00220
"WHERE cur_id=si_page AND {$this->mTextcond} " .
00221
"{$searchnamespaces} {$redircond} " .
00222
"LIMIT {$offset}, {$limit}";
00223
$res2 =
wfQuery( $sql,
DB_READ, $fname );
00224 $num = $num +
wfNumRows($res2);
00225
00226
if ( $num == $limit ) {
00227 $top =
wfShowingResults( $offset, $limit);
00228 }
else {
00229 $top =
wfShowingResultsNum( $offset, $limit, $num );
00230 }
00231
$wgOut->addHTML(
"<p>{$top}</p>\n" );
00232
00233
# For powersearch
00234
00235 $a2l =
"" ;
00236 $akk = array_keys( $this->addtoquery ) ;
00237 foreach ( $akk AS $ak ) {
00238 $a2l .=
"&{$ak}={$this->addtoquery[$ak]}" ;
00239 }
00240
00241 $sl =
wfViewPrevNext( $offset, $limit,
"",
00242
"search=" .
wfUrlencode( $this->mUsertext ) . $a2l );
00243
$wgOut->addHTML(
"<br />{$sl}\n" );
00244
00245 $foundsome =
false;
00246
00247
if ( 0 ==
wfNumRows( $res1 ) ) {
00248
$wgOut->addHTML(
"<h2>" .
wfMsg(
"notitlematches" ) .
00249
"</h2>\n" );
00250 }
else {
00251 $foundsome =
true;
00252 $off = $offset + 1;
00253
$wgOut->addHTML(
"<h2>" .
wfMsg(
"titlematches" ) .
00254
"</h2>\n<ol start='{$off}'>" );
00255
00256
while (
$row =
wfFetchObject( $res1 ) ) {
00257 $this->
showHit( $row );
00258 }
00259
wfFreeResult( $res1 );
00260
$wgOut->addHTML(
"</ol>\n" );
00261 }
00262
00263
if ( 0 ==
wfNumRows( $res2 ) ) {
00264
$wgOut->addHTML(
"<h2>" .
wfMsg(
"notextmatches" ) .
00265
"</h2>\n" );
00266 }
else {
00267 $foundsome =
true;
00268 $off = $offset + 1;
00269
$wgOut->addHTML(
"<h2>" .
wfMsg(
"textmatches" ) .
"</h2>\n" .
00270
"<ol start='{$off}'>" );
00271
while (
$row =
wfFetchObject( $res2 ) ) {
00272 $this->
showHit( $row );
00273 }
00274
wfFreeResult( $res2 );
00275
$wgOut->addHTML(
"</ol>\n" );
00276 }
00277
if ( ! $foundsome ) {
00278
$wgOut->addHTML(
"<p>" .
wfMsg(
"nonefound" ) .
"</p>\n" );
00279 }
00280
$wgOut->addHTML(
"<p>{$sl}</p>\n" );
00281
$wgOut->addHTML( $powersearch );
00282 }
00283 }
00284
00285 function
legalSearchChars()
00286 {
00287
$lc =
"A-Za-z_'0-9\\x80-\\xFF\\-";
00288
return $lc;
00289 }
00290
00291 function
parseQuery()
00292 {
00293 global
$wgDBminWordLen,
$wgLang,
$wgDBmysql4;
00294
00295
if(
$wgDBmysql4 ) {
00296
# Use cleaner boolean search if available
00297
return $this->
parseQuery4();
00298 }
00299
# on non mysql4 database: get list of words we don't want to search for
00300
require_once(
"FulltextStoplist.php" );
00301
00302
$lc =
SearchEngine::legalSearchChars() .
"()";
00303 $q = preg_replace(
"/([()])/",
" \\1 ", $this->mUsertext );
00304 $q = preg_replace(
"/\\s+/",
" ", $q );
00305 $w = explode(
" ", strtolower( trim( $q ) ) );
00306
00307 $last = $cond =
"";
00308 foreach ( $w as $word ) {
00309 $word =
$wgLang->stripForSearch( $word );
00310
if (
"and" == $word ||
"or" == $word ||
"not" == $word
00311 ||
"(" == $word ||
")" == $word ) {
00312 $cond .=
" " . strtoupper( $word );
00313 $last =
"";
00314 }
else if ( strlen( $word ) <
$wgDBminWordLen ) {
00315
continue;
00316 }
else if ( FulltextStoplist::inList( $word ) ) {
00317
continue;
00318 }
else {
00319
if (
"" != $last ) { $cond .=
" AND"; }
00320 $cond .=
" (MATCH (##field##) AGAINST ('" .
00321
wfStrencode( $word ).
"'))";
00322 $last = $word;
00323 array_push( $this->mSearchterms,
"\\b" . $word .
"\\b" );
00324 }
00325 }
00326
if ( 0 == count( $this->mSearchterms ) ) {
return; }
00327
00328 $this->
mTitlecond =
"(" . str_replace(
"##field##",
00329
"si_title", $cond ) .
" )";
00330
00331 $this->
mTextcond =
"(" . str_replace(
"##field##",
00332
"si_text", $cond ) .
" AND (cur_is_redirect=0) )";
00333 }
00334
00335 function
parseQuery4()
00336 {
00337 global
$wgLang;
00338
$lc =
SearchEngine::legalSearchChars();
00339 $searchon =
"";
00340 $this->
mSearchterms = array();
00341
00342
# FIXME: This doesn't handle parenthetical expressions.
00343
if( preg_match_all( '/([-+<>~]?)(([' . $lc . ']+)(\*?)|
"[^"]*
")/',
00344
$this->mUsertext, $m, PREG_SET_ORDER ) ) {
00345
foreach( $m as $terms ) {
00346
if( $searchon !== "" ) $searchon .= " ";
00347
if( $this->mStrictMatching && ($terms[1] == "") ) {
00348
$terms[1] = "+
";
00349
}
00350
$searchon .= $terms[1] . $wgLang->stripForSearch( $terms[2] );
00351
if( $terms[3] ) {
00352
$regexp = preg_quote( $terms[3] );
00353
if( $terms[4] ) $regexp .= "[0-9A-Za-z_]+
";
00354
} else {
00355
$regexp = preg_quote( str_replace( '"', '', $terms[2] ) );
00356 }
00357 $this->
mSearchterms[] = $regexp;
00358 }
00359
wfDebug(
"Would search with '$searchon'\n" );
00360
wfDebug(
"Match with /\b" . implode( '\b|\b', $this->mSearchterms ) .
"\b/\n" );
00361 }
else {
00362
wfDebug(
"Can't understand search query '$this->mUsertext'\n" );
00363 }
00364
00365 $searchon =
wfStrencode( $searchon );
00366 $this->
mTitlecond =
" MATCH(si_title) AGAINST('$searchon' IN BOOLEAN MODE)";
00367 $this->
mTextcond =
" (MATCH(si_text) AGAINST('$searchon' IN BOOLEAN MODE) AND cur_is_redirect=0)";
00368 }
00369
00370 function
showHit( $row )
00371 {
00372 global
$wgUser,
$wgOut;
00373
00374 $t = Title::makeName( $row->cur_namespace, $row->cur_title );
00375 $sk =
$wgUser->getSkin();
00376
00377 $contextlines =
$wgUser->getOption(
"contextlines" );
00378
if (
"" == $contextlines ) { $contextlines = 5; }
00379 $contextchars =
$wgUser->getOption(
"contextchars" );
00380
if (
"" == $contextchars ) { $contextchars = 50; }
00381
00382 $link = $sk->makeKnownLink( $t,
"" );
00383 $size =
wfMsg(
"nbytes", strlen( $row->cur_text ) );
00384
$wgOut->addHTML(
"<li>{$link} ({$size})" );
00385
00386
$lines = explode(
"\n", $row->cur_text );
00387 $pat1 =
"/(.*)(" . implode(
"|", $this->mSearchterms ) .
")(.*)/i";
00388 $lineno = 0;
00389
00390 foreach ( $lines as $line ) {
00391
if ( 0 == $contextlines ) {
break; }
00392 --$contextlines;
00393 ++$lineno;
00394
if ( ! preg_match( $pat1, $line, $m ) ) {
continue; }
00395
00396 $pre = $m[1];
00397
if ( 0 == $contextchars ) { $pre =
"..."; }
00398
else {
00399
if ( strlen( $pre ) > $contextchars ) {
00400 $pre =
"..." . substr( $pre, -$contextchars );
00401 }
00402 }
00403 $pre =
wfEscapeHTML( $pre );
00404
00405
if ( count( $m ) < 3 ) { $post =
""; }
00406
else { $post = $m[3]; }
00407
00408
if ( 0 == $contextchars ) { $post =
"..."; }
00409
else {
00410
if ( strlen( $post ) > $contextchars ) {
00411 $post = substr( $post, 0, $contextchars ) .
"...";
00412 }
00413 }
00414 $post =
wfEscapeHTML( $post );
00415 $found =
wfEscapeHTML( $m[2] );
00416
00417
$line =
"{$pre}{$found}{$post}";
00418 $pat2 =
"/(" . implode(
"|", $this->mSearchterms ) .
")/i";
00419
$line = preg_replace( $pat2,
00420
"<font color='red'>\\1</font>", $line );
00421
00422
$wgOut->addHTML(
"<br /><small>{$lineno}: {$line}</small>\n" );
00423 }
00424
$wgOut->addHTML(
"</li>\n" );
00425 }
00426
00427 function
goResult()
00428 {
00429 global
$wgOut,
$wgRequest,
$wgGoToEdit;
00430 global
$wgDisableTextSearch;
00431 $fname =
"SearchEngine::goResult";
00432
00433 $search = trim( $wgRequest->getText(
"search" ) );
00434
00435
# Try to go to page as entered.
00436
#
00437
$t = Title::newFromText( $search );
00438
00439
# If the string cannot be used to create a title
00440
if(
false == $t ){
00441 $this->showResults();
00442
return;
00443 }
00444
00445
# Exact match? No need to look further.
00446
if ( $t->getNamespace() ==
NS_SPECIAL || 0 != $t->getArticleID() ) {
00447
$wgOut->redirect( $t->getFullURL() );
00448
return;
00449 }
00450
00451
# Now try all lower case (i.e. first letter capitalized)
00452
#
00453
$t = Title::newFromText( strtolower( $search ) );
00454
if ( 0 != $t->getArticleID() ) {
00455
$wgOut->redirect( $t->getFullURL() );
00456
return;
00457 }
00458
00459
# Now try capitalized string
00460
#
00461
$t = Title::newFromText( ucwords( strtolower( $search ) ) );
00462
if ( 0 != $t->getArticleID() ) {
00463
$wgOut->redirect( $t->getFullURL() );
00464
return;
00465 }
00466
00467
# Now try all upper case
00468
#
00469
$t = Title::newFromText( strtoupper( $search ) );
00470
if ( 0 != $t->getArticleID() ) {
00471
$wgOut->redirect( $t->getFullURL() );
00472
return;
00473 }
00474
00475
# Entering an IP address goes to the contributions page
00476
if ( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $search ) ) {
00477
$title = Title::makeTitle(
NS_SPECIAL,
"Contributions" );
00478
$wgOut->redirect( $
title->getFullUrl(
"target=$search" ) );
00479
return;
00480 }
00481
00482
# No match, generate an edit URL
00483
$t = Title::newFromText( $this->mUsertext );
00484
00485
# If the feature is enabled, go straight to the edit page
00486
if (
$wgGoToEdit ) {
00487
$wgOut->redirect( $t->getFullURL(
"action=edit" ) );
00488
return;
00489 }
00490
00491
if( $t ) {
00492 $editurl = $t->escapeLocalURL(
"action=edit" );
00493 }
else {
00494 $editurl =
""; # ??
00495 }
00496
$wgOut->addHTML(
"<p>" .
wfMsg(
"nogomatch", $editurl ) .
"</p>\n" );
00497
00498
# Try a fuzzy title search
00499
$anyhit =
false;
00500 global
$wgDisableFuzzySearch;
00501
if(!
$wgDisableFuzzySearch ){
00502 foreach( array(
NS_MAIN,
NS_WP,
NS_USER,
NS_IMAGE,
NS_MEDIAWIKI) as $
namespace){
00503 $anyhit |=
SearchEngine::doFuzzyTitleSearch( $search, $
namespace );
00504 }
00505 }
00506
00507
if( ! $anyhit ){
00508
return $this->showResults();
00509 }
00510 }
00511
00512 function
doFuzzyTitleSearch( $search, $
namespace ){
00513 global
$wgLang,
$wgOut;
00514
00515 $this->setupPage();
00516
00517 $sstr = ucfirst($search);
00518 $sstr = str_replace(
" ",
"_", $sstr);
00519 $fuzzymatches =
SearchEngine::fuzzyTitles( $sstr, $
namespace );
00520 $fuzzymatches = array_slice($fuzzymatches, 0, 10);
00521 $slen = strlen( $search );
00522 $wikitext =
"";
00523 foreach($fuzzymatches as $res){
00524 $t = str_replace(
"_",
" ", $res[1]);
00525 $tfull =
$wgLang->getNsText( $
namespace ) .
":$t|$t";
00526
if( $namespace ==
NS_MAIN )
00527 $tfull =
"$t";
00528 $distance =
$res[0];
00529 $closeness = (strlen( $search ) - $distance) / strlen( $search );
00530 $percent = intval( $closeness * 100 ) .
"%";
00531 $stars = str_repeat(
"*", ceil(5 * $closeness) );
00532 $wikitext .=
"* [[$tfull]] $percent ($stars)\n";
00533 }
00534
if( $wikitext ){
00535
if( $namespace !=
NS_MAIN )
00536 $wikitext =
"=== " .
$wgLang->getNsText( $
namespace ) .
" ===\n" . $wikitext;
00537
$wgOut->addWikiText( $wikitext );
00538
return true;
00539 }
00540
return false;
00541 }
00542
00543 function
fuzzyTitles( $sstr, $
namespace = NS_MAIN ){
00544 $span = 0.10;
00545 $tolerance = 0.35;
00546 $slen = strlen($sstr);
00547 $tolerance_count = ceil($tolerance * $slen);
00548 $spanabs = ceil($slen * (1 + $span)) - $slen;
00549
# print "Word: $sstr, len = $slen, range = [$min, $max], tolerance_count = $tolerance_count<BR>\n";
00550
$result = array();
00551 $cnt = 0;
00552
for(
$i=0;
$i <= $spanabs;
$i++ ){
00553 $titles =
SearchEngine::getTitlesByLength( $slen + $i, $
namespace );
00554
if(
$i != 0) {
00555 $titles = array_merge($titles, SearchEngine::getTitlesByLength( $slen - $i, $
namespace ) );
00556 }
00557 foreach($titles as $t){
00558
$d = levenshtein($sstr, $t);
00559
if(
$d < $tolerance_count)
00560 $result[] = array($d, $t);
00561 $cnt++;
00562 }
00563 }
00564 usort($result,
"SearchEngine_pcmp");
00565
return $result;
00566 }
00567
00568 function
getTitlesByLength($aLength, $aNamespace = 0){
00569 global
$wgMemc,
$wgDBname;
00570
00571
00572
if( $this->all_titles ){
00573
if( isset( $this->all_titles[$aLength][$aNamespace] ) ){
00574
return $this->all_titles[$aLength][$aNamespace];
00575 }
else {
00576
return array();
00577 }
00578 }
00579
00580 $mkey =
"$wgDBname:titlesbylength:$aLength:$aNamespace";
00581 $mkeyts =
"$wgDBname:titlesbylength:createtime";
00582 $ts =
$wgMemc->get( $mkeyts );
00583 $result =
$wgMemc->get( $mkey );
00584
00585
if( time() - $ts < 3600 ){
00586
00587
00588
return is_array( $result ) ? $result : array();
00589 }
00590
00591
$wgMemc->set( $mkeyts, time() );
00592
00593
$res =
wfQuery(
"SELECT cur_title, cur_namespace FROM cur",
DB_READ);
00594 $titles = array();
00595
while( $obj =
wfFetchObject( $res ) ){
00596
$title = $obj->cur_title;
00597 $ns = $obj->cur_namespace;
00598 $len = strlen( $
title );
00599 $titles[$len][$ns][] =
$title;
00600 }
00601 foreach($titles as $length => $length_arr){
00602 foreach($length_arr as $ns => $title_arr){
00603 $mkey =
"$wgDBname:titlesbylength:$length:$ns";
00604
$wgMemc->set( $mkey, $title_arr, 3600 * 24 );
00605 }
00606 }
00607 $this->all_titles = $titles;
00608
if( isset( $titles[$aLength][$aNamespace] ) )
00609
return $titles[$aLength][$aNamespace];
00610
else
00611
return array();
00612 }
00613 }
00614
00615 function
SearchEngine_pcmp($a, $b){
return $a[0] - $b[0]; }
00616
00617 ?>