\$[SearchFor] $HTMLVSpace\$MatchList $HTMLVSpace\$[SearchFound]$HTMLVSpace"); SDV($SearchQuery, str_replace('$', '$', htmlspecialchars(stripmagic(@$_REQUEST['q']), ENT_NOQUOTES))); XLSDV('en', array( 'SearchFor' => 'Results of search for $Needle:', 'SearchFound' => '$MatchCount pages found out of $MatchSearched pages searched.')); Markup('pagelist', 'directives', '/\\(:pagelist(\\s+.*?)?:\\)/ei', "FmtPageList('\$MatchList', \$pagename, array('o' => PSS('$1 ')))"); Markup('searchresults', 'directives', '/\\(:searchresults(\\s+.*?)?:\\)/ei', "FmtPageList(\$GLOBALS['SearchResultsFmt'], \$pagename, array('o' => PSS('$1'), 'req' => 1))"); Markup('searchbox', '>links', '/\\(:searchbox(\\s.*?)?:\\)/e', "SearchBox(\$pagename, ParseArgs(PSS('$1')))"); SDV($HandleActions['search'], 'HandleSearchA'); SDV($HandleAuth['search'], 'read'); ## SearchBox generates the output of the (:searchbox:) markup. ## If $SearchBoxFmt is defined, that is used, otherwise a searchbox ## is generated. Options include group=, size=, label=. function SearchBox($pagename, $opt) { global $SearchBoxFmt, $SearchBoxOpt, $SearchQuery, $EnablePathInfo; if (isset($SearchBoxFmt)) return FmtPageName($SearchBoxFmt, $pagename); SDVA($SearchBoxOpt, array('size' => '40', 'label' => FmtPageName('$[Search]', $pagename), 'group' => @$_REQUEST['group'], 'value' => $SearchQuery)); $opt = array_merge((array)$SearchBoxOpt, (array)$opt); $group = $opt['group']; $out[] = FmtPageName(" class='wikisearch' action='\$PageUrl' method='get'>", $pagename); if (!IsEnabled($EnablePathInfo, 0)) $out[] = ""; if ($group) $out[] = ""; $out[] = ""; return "
'.Keep($out).''; PRR(); return $out; } ## MakePageList generates a list of pages using the specifications given ## by $opt. function MakePageList($pagename, $opt) { global $MakePageListOpt, $SearchPatterns, $EnablePageListProtect, $PCache, $FmtV; StopWatch('MakePageList begin'); SDVA($MakePageListOpt, array('list' => 'default')); $opt = array_merge((array)$MakePageListOpt, $opt); $readf = $opt['readf']; # we have to read the page if order= is anything but name $order = $opt['order']; $readf |= $order && ($order!='name') && ($order!='-name'); $pats = @(array)$SearchPatterns[$opt['list']]; if (@$opt['group']) array_unshift($pats, "/^({$opt['group']})\./i"); # inclp/exclp contain words to be included/excluded. $inclp = array(); $exclp = array(); foreach((array)@$opt[''] as $i) { $inclp[] = '/'.preg_quote($i, '/').'/i'; } foreach((array)@$opt['+'] as $i) { $inclp[] = '/'.preg_quote($i, '/').'/i'; } foreach((array)@$opt['-'] as $i) { $exclp[] = '/'.preg_quote($i, '/').'/i'; } $searchterms = count($inclp) + count($exclp); $readf += $searchterms; # forced read if incl/excl if (@$opt['trail']) { $trail = ReadTrail($pagename, $opt['trail']); foreach($trail as $tstop) { $pn = $tstop['pagename']; $list[] = $pn; $tstop['parentnames'] = array(); PCache($pn, $tstop); } foreach($trail as $tstop) $PCache[$tstop['pagename']]['parentnames'][] = $trail[$tstop['parent']]['pagename']; } else $list = ListPages($pats); if (IsEnabled($EnablePageListProtect, 0)) $readf = 1000; $matches = array(); $FmtV['$MatchSearched'] = count($list); # link= (backlinks) if (@$opt['link']) { $link = MakePageName($pagename, $opt['link']); $linkpat = "/(^|,)$link(,|$)/i"; $readf++; $xlist = BacklinksTo($link, false); $list = array_diff($list, $xlist); } $xlist = array(); StopWatch('MakePageList scan'); foreach((array)$list as $pn) { if ($readf) { $page = ($readf >= 1000) ? RetrieveAuthPage($pn, 'read', false, READPAGE_CURRENT) : ReadPage($pn, READPAGE_CURRENT); if (!$page) continue; if (@$linkpat && !preg_match($linkpat, @$page['targets'])) { $PCache[$pn]['targets'] = @$page['targets']; $xlist[]=$pn; continue; } if ($searchterms) { $text = $pn."\n".@$page['targets']."\n".@$page['text']; foreach($inclp as $i) if (!preg_match($i, $text)) continue 2; foreach($exclp as $i) if (preg_match($i, $text)) continue 2; } $page['size'] = strlen(@$page['text']); } else $page = array(); $page['pagename'] = $page['name'] = $pn; PCache($pn, $page); $matches[] = & $PCache[$pn]; } StopWatch('MakePageList sort'); SortPageList($matches, $order); StopWatch('MakePageList update'); if ($xlist) LinkIndexUpdate($xlist); StopWatch('MakePageList end'); return $matches; } function SortPageList(&$matches, $order) { $code = ''; foreach(preg_split("/[\\s,|]+/", $order, -1, PREG_SPLIT_NO_EMPTY) as $o) { if ($o{0}=='-') { $r = '-'; $o = substr($o, 1); } else $r = ''; if ($o == 'size' || $o == 'time') $code .= "\$c = @(\$x['$o']-\$y['$o']); "; else $code .= "\$c = @strcasecmp(\$x['$o'],\$y['$o']); "; $code .= "if (\$c) return $r\$c;\n"; } if ($code) uasort($matches, create_function('$x,$y', "$code return 0;")); } ## HandleSearchA performs ?action=search. It's basically the same ## as ?action=browse, except it takes its contents from Site.Search. function HandleSearchA($pagename, $level = 'read') { global $PageSearchForm, $FmtV, $HandleSearchFmt, $PageStartFmt, $PageEndFmt; SDV($HandleSearchFmt,array(&$PageStartFmt, '$PageText', &$PageEndFmt)); SDV($PageSearchForm, '$[$SiteGroup/Search]'); PCache($pagename, RetrieveAuthPage($pagename, 'read')); $form = ReadPage(FmtPageName($PageSearchForm, $pagename), READPAGE_CURRENT); $text = @$form['text']; if (!$text) $text = '(:searchresults:)'; $FmtV['$PageText'] = MarkupToHTML($pagename,$text); PrintFmt($pagename, $HandleSearchFmt); } ######################################################################## ## The functions below provide different formatting options for ## the output list, controlled by the fmt= parameter and the ## $FPLFunctions hash. ######################################################################## ## $FPLFunctions is a list of functions associated with fmt= options SDVA($FPLFunctions, array( 'bygroup' => 'FPLByGroup', 'simple' => 'FPLSimple', 'group' => 'FPLGroup')); ## FPLByGroup provides a simple listing of pages organized by group function FPLByGroup($pagename, &$matches, $opt) { global $FPLByGroupStartFmt, $FPLByGroupEndFmt, $FPLByGroupGFmt, $FPLByGroupIFmt, $FPLByGroupOpt; SDV($FPLByGroupStartFmt,"
"); SDV($FPLByGroupEndFmt,'
'); SDV($FPLByGroupGFmt,"
\$Group /
\n"); SDV($FPLByGroupIFmt,"
\$Name
\n"); SDVA($FPLByGroupOpt, array('readf' => 0, 'order' => 'name')); $matches = MakePageList($pagename, array_merge((array)$FPLByGroupOpt, $opt)); if (@$opt['count']) array_splice($matches, $opt['count']); $out = array(); foreach($matches as $pc) { $pgroup = FmtPageName($FPLByGroupGFmt, $pc['pagename']); if ($pgroup != @$lgroup) { $out[] = $pgroup; $lgroup = $pgroup; } $out[] = FmtPageName($FPLByGroupIFmt, $pc['pagename']); } return FmtPageName($FPLByGroupStartFmt, $pagename) . implode('', $out) . FmtPageName($FPLByGroupEndFmt, $pagename); } ## FPLSimple provides a simple bullet list of pages function FPLSimple($pagename, &$matches, $opt) { global $FPLSimpleStartFmt, $FPLSimpleIFmt, $FPLSimpleEndFmt, $FPLSimpleOpt; SDV($FPLSimpleStartFmt, ""); SDV($FPLSimpleIFmt, "
  • \$FullName
  • "); SDVA($FPLSimpleOpt, array('readf' => 0)); $topt['order'] = (@$opt['trail']) ? '' : 'name'; $matches = MakePageList($pagename, array_merge($topt, (array)$FPLSimpleOpt, $opt)); if (@$opt['count']) array_splice($matches, $opt['count']); $out = array(); foreach($matches as $pc) $out[] = FmtPageName($FPLSimpleIFmt, $pc['pagename']); return FmtPageName($FPLSimpleStartFmt, $pagename) . implode('', $out) . FmtPageName($FPLSimpleEndFmt, $pagename); } ## FPLGroup provides a simple bullet list of groups function FPLGroup($pagename, &$matches, $opt) { global $FPLGroupStartFmt, $FPLGroupIFmt, $FPLGroupEndFmt, $FPLGroupOpt; SDV($FPLGroupStartFmt, ""); SDV($FPLGroupIFmt, "
  • \$Group
  • "); SDVA($FPLGroupOpt, array('readf' => 0, 'order' => 'name')); $matches = MakePageList($pagename, array_merge((array)$FPLGroupOpt, $opt)); $out = array(); foreach($matches as $pc) { $group = preg_replace('/\\.[^.]+$/', '', $pc['pagename']); if (@!$seen[$group]++) { $out[] = FmtPageName($FPLGroupIFmt, $pc['pagename']); if ($opt['count'] && count($out) >= $opt['count']) break; } } return FmtPageName($FPLGroupStartFmt, $pagename) . implode('', $out) . FmtPageName($FPLGroupEndFmt, $pagename); } ######################################################################## ## The functions below optimize backlinks by maintaining an index ## file of link cross references (the "link index"). ######################################################################## ## The BacklinksTo($pagename, $incl) function reads the current ## linkindex file and returns all listed pages that have $pagename ## as a target. If $incl is false, then BacklinksTo returns ## the pages in the linkindex that *don't* have $pagename as a target. ## Note that if the linkindex is incomplete then so is the returned list. function BacklinksTo($pagename, $incl=true) { global $LinkIndexFile; if (!$LinkIndexFile) return array(); StopWatch('BacklinksTo begin'); $excl = ! $incl; $pagelist = array(); $fp = @fopen($LinkIndexFile, 'r'); if ($fp) { $linkpat = "/[=,]{$pagename}[\n,]/i"; while (!feof($fp)) { $line = fgets($fp, 4096); while (substr($line, -1, 1) != "\n" && !feof($fp)) $line .= fgets($fp, 4096); if (strpos($line, '=') === false) continue; if (preg_match($linkpat, $line) xor $excl) { list($n,$t) = explode('=', $line, 2); $pagelist[] = $n; } } fclose($fp); } StopWatch('BacklinksTo end'); return $pagelist; } ## The LinkIndexUpdate($pagelist) function updates the linkindex ## file with the target information for the pages in $pagelist. ## If the targets are cached then LinkIndexUpdate uses that, ## otherwise the pages are read to get the current targets. function LinkIndexUpdate($pagelist) { global $LinkIndexFile, $PCache, $LinkIndexTime; SDV($LinkIndexTime, 10); if (!$pagelist || !$LinkIndexFile) return; StopWatch('LinkIndexUpdate begin'); $pagelist = (array)$pagelist; Lock(2); $ofp = fopen("$LinkIndexFile,new", 'w'); $timeout = time() + $LinkIndexTime; foreach($pagelist as $n) { if (time() > $timeout) break; if (isset($PCache[$n]['targets'])) $targets=$PCache[$n]['targets']; else { $page = ReadPage($n, READPAGE_CURRENT); if (!$page) continue; $targets = @$page['targets']; } fputs($ofp, "$n=$targets\n"); } $ifp = @fopen($LinkIndexFile, 'r'); if ($ifp) { while (!feof($ifp)) { $line = fgets($ifp, 4096); while (substr($line, -1, 1) != "\n" && !feof($ifp)) $line .= fgets($ifp, 4096); $i = strpos($line, '='); if ($i === false) continue; $n = substr($line, 0, $i); if (in_array($n, $pagelist)) continue; fputs($ofp, $line); } fclose($ifp); } fclose($ofp); if (file_exists($LinkIndexFile)) unlink($LinkIndexFile); rename("$LinkIndexFile,new", $LinkIndexFile); fixperms($LinkIndexFile); StopWatch('LinkIndexUpdate end'); } ## PostLinkIndex is inserted into $EditFunctions to update ## the linkindex whenever a page is saved. function PostLinkIndex($pagename, &$page, &$new) { global $IsPagePosted, $PCache; if (!$IsPagePosted) return; $PCache[$pagename]['targets'] = $new['targets']; LinkIndexUpdate($pagename); }