2 rcs_id('$Id: stdlib.php,v 1.18 2001-01-01 23:34:57 ahollosi Exp $');
4 Standard functions for Wiki functionality
5 LinkRelatedPages($dbi, $pagename)
6 GeneratePage($template, $content, $name, $hash)
7 LinkExistingWikiWord($wikiword)
8 LinkUnknownWikiWord($wikiword)
14 CookSpaces($pagearray)
16 SetHTMLOutputMode($newmode, $depth)
17 UpdateRecentChanges($dbi, $pagename, $isnewpage)
18 ParseAndLink($bracketlink)
19 ExtractWikiPageLinks($content)
24 function ExitWiki($errormsg)
29 if($exitwiki) // just in case CloseDataBase calls us
36 print "<P><hr noshade><h2>" . gettext("WikiFatalError") . "</h2>\n";
38 print "\n</BODY></HTML>";
44 function LinkRelatedPages($dbi, $pagename)
46 // currently not supported everywhere
47 if(!function_exists('GetWikiPageLinks'))
50 $links = GetWikiPageLinks($dbi, $pagename);
53 $txt .= sprintf (gettext ("%d best incoming links:"), NUM_RELATED_PAGES);
55 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
56 if(isset($links['in'][$i])) {
57 list($name, $score) = $links['in'][$i];
58 $txt .= LinkExistingWikiWord($name) . " ($score), ";
63 $txt .= sprintf (gettext ("%d best outgoing links:"), NUM_RELATED_PAGES);
65 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
66 if(isset($links['out'][$i])) {
67 list($name, $score) = $links['out'][$i];
68 if(IsWikiPage($dbi, $name))
69 $txt .= LinkExistingWikiWord($name) . " ($score), ";
74 $txt .= sprintf (gettext ("%d most popular nearby:"), NUM_RELATED_PAGES);
76 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
77 if(isset($links['popular'][$i])) {
78 list($name, $score) = $links['popular'][$i];
79 $txt .= LinkExistingWikiWord($name) . " ($score), ";
87 function GeneratePage($template, $content, $name, $hash)
89 global $ScriptUrl, $AllowedProtocols, $templates;
90 global $datetimeformat, $dbi, $logo, $FieldSeparator;
95 function _dotoken ($id, $val, &$page) {
96 global $FieldSeparator;
97 $page = str_replace("$FieldSeparator#$id$FieldSeparator#",
101 function _iftoken ($id, $condition, &$page) {
102 global $FieldSeparator;
104 // line based IF directive
105 $lineyes = "$FieldSeparator#IF $id$FieldSeparator#";
106 $lineno = "$FieldSeparator#IF !$id$FieldSeparator#";
107 // block based IF directive
108 $blockyes = "$FieldSeparator#IF:$id$FieldSeparator#";
109 $blockyesend = "$FieldSeparator#ENDIF:$id$FieldSeparator#";
110 $blockno = "$FieldSeparator#IF:!$id$FieldSeparator#";
111 $blocknoend = "$FieldSeparator#ENDIF:!$id$FieldSeparator#";
114 $page = str_replace($lineyes, '', $page);
115 $page = str_replace($blockyes, '', $page);
116 $page = str_replace($blockyesend, '', $page);
117 $page = preg_replace("/$blockno(.*?)$blocknoend/s", '', $page);
118 $page = ereg_replace("${lineno}[^\n]*\n", '', $page);
120 $page = str_replace($lineno, '', $page);
121 $page = str_replace($blockno, '', $page);
122 $page = str_replace($blocknoend, '', $page);
123 $page = preg_replace("/$blockyes(.*?)$blockyesend/s", '', $page);
124 $page = ereg_replace("${lineyes}[^\n]*\n", '', $page);
128 $page = join('', file($templates[$template]));
129 $page = str_replace('###', "$FieldSeparator#", $page);
131 // valid for all pagetypes
132 _iftoken('COPY', isset($hash['copy']), $page);
133 _iftoken('LOCK', (isset($hash['flags']) &&
134 ($hash['flags'] & FLAG_PAGE_LOCKED)), $page);
135 _iftoken('ADMIN', defined('WIKI_ADMIN'), $page);
137 _dotoken('SCRIPTURL', $ScriptUrl, $page);
138 _dotoken('PAGE', htmlspecialchars($name), $page);
139 _dotoken('ALLOWEDPROTOCOLS', $AllowedProtocols, $page);
140 _dotoken('LOGO', $logo, $page);
142 // invalid for messages (search results, error messages)
143 if ($template != 'MESSAGE') {
144 _dotoken('PAGEURL', rawurlencode($name), $page);
145 _dotoken('LASTMODIFIED',
146 date($datetimeformat, $hash['lastmodified']), $page);
147 _dotoken('LASTAUTHOR', $hash['author'], $page);
148 _dotoken('VERSION', $hash['version'], $page);
149 if (strstr($page, "$FieldSeparator#HITS$FieldSeparator#")) {
150 _dotoken('HITS', GetHitCount($dbi, $name), $page);
152 if (strstr($page, "$FieldSeparator#RELATEDPAGES$FieldSeparator#")) {
153 _dotoken('RELATEDPAGES', LinkRelatedPages($dbi, $name), $page);
157 // valid only for EditLinks
158 if ($template == 'EDITLINKS') {
159 for ($i = 1; $i <= NUM_LINKS; $i++) {
160 $ref = isset($hash['refs'][$i]) ? $hash['refs'][$i] : '';
161 _dotoken("R$i", $ref, $page);
165 _dotoken('CONTENT', $content, $page);
170 function LinkExistingWikiWord($wikiword, $linktext='') {
172 $enc_word = rawurlencode($wikiword);
174 $linktext = htmlspecialchars($wikiword);
175 return "<a href=\"$ScriptUrl?$enc_word\">$linktext</a>";
178 function LinkUnknownWikiWord($wikiword, $linktext='') {
180 $enc_word = rawurlencode($wikiword);
182 $linktext = htmlspecialchars($wikiword);
183 return "<u>$linktext</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
186 function LinkURL($url, $linktext='') {
188 if(ereg("[<>\"]", $url)) {
189 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
193 $linktext = htmlspecialchars($url);
194 return "<a href=\"$url\">$linktext</a>";
198 function LinkImage($url, $alt="[External Image]") {
200 if(ereg("[<>\"]", $url)) {
201 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
203 return "<img src=\"$url\" ALT=\"$alt\">";
207 function RenderQuickSearch($value = "") {
209 return "<form action=\"$ScriptUrl\">\n" .
210 "<input type=text size=30 name=search value=\"$value\">\n" .
211 "<input type=submit value=\"". gettext("Search") .
215 function RenderFullSearch($value = "") {
217 return "<form action=\"$ScriptUrl\">\n" .
218 "<input type=text size=30 name=full value=\"$value\">\n" .
219 "<input type=submit value=\"". gettext("Search") .
223 function RenderMostPopular() {
224 global $ScriptUrl, $dbi;
226 $query = InitMostPopular($dbi, MOST_POPULAR_LIST_LENGTH);
228 while ($qhash = MostPopularNextMatch($dbi, $query)) {
229 $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
231 $result .= "</DL>\n";
236 function ParseAdminTokens($line) {
239 while (preg_match("/%%ADMIN-INPUT-(.*?)-(\w+)%%/", $line, $matches)) {
240 $head = str_replace("_", " ", $matches[2]);
241 $form = "<FORM ACTION=\"$ScriptUrl\" METHOD=POST>"
242 ."$head: <INPUT NAME=$matches[1] SIZE=20> "
243 ."<INPUT TYPE=SUBMIT VALUE=\"" . gettext("Go") . "\">"
245 $line = str_replace($matches[0], $form, $line);
250 // converts spaces to tabs
251 function CookSpaces($pagearray) {
252 return preg_replace("/ {3,8}/", "\t", $pagearray);
257 var $items = array();
260 function push($item) {
261 $this->items[$this->size] = $item;
267 if ($this->size == 0) {
268 return false; // stack is empty
271 return $this->items[$this->size];
280 return $this->items[$this->size - 1];
286 // end class definition
289 // I couldn't move this to lib/config.php because it
290 // wasn't declared yet.
294 Wiki HTML output can, at any given time, be in only one mode.
295 It will be something like Unordered List, Preformatted Text,
296 plain text etc. When we change modes we have to issue close tags
297 for one mode and start tags for another.
300 function SetHTMLOutputMode($tag, $tagdepth, $tabcount) {
304 if ($tagdepth == SINGLE_DEPTH) {
305 if ($tabcount < $stack->cnt()) {
306 // there are fewer tabs than stack,
307 // reduce stack to that tab count
308 while ($stack->cnt() > $tabcount) {
309 $closetag = $stack->pop();
310 if ($closetag == false) {
311 //echo "bounds error in tag stack";
314 $retvar .= "</$closetag>\n";
317 // if list type isn't the same,
318 // back up one more and push new tag
319 if ($tag != $stack->top()) {
320 $closetag = $stack->pop();
321 $retvar .= "</$closetag><$tag>\n";
325 } elseif ($tabcount > $stack->cnt()) {
326 // we add the diff to the stack
327 // stack might be zero
328 while ($stack->cnt() < $tabcount) {
330 $retvar .= "<$tag>\n";
332 if ($stack->cnt() > 10) {
333 // arbitrarily limit tag nesting
334 ExitWiki(gettext ("Stack bounds exceeded in SetHTMLOutputMode"));
339 if ($tag == $stack->top()) {
342 $closetag = $stack->pop();
343 #echo "</$closetag>\n";
345 $retvar .= "</$closetag>\n";
346 $retvar .= "<$tag>\n";
351 } elseif ($tagdepth == ZERO_DEPTH) {
352 // empty the stack for $depth == 0;
353 // what if the stack is empty?
354 if ($tag == $stack->top()) {
357 while ($stack->cnt() > 0) {
358 $closetag = $stack->pop();
359 #echo "</$closetag>\n";
360 $retvar .= "</$closetag>\n";
365 $retvar .= "<$tag>\n";
371 ExitWiki ("Passed bad tag depth value in SetHTMLOutputMode");
377 // end SetHTMLOutputMode
381 // The Recent Changes file is solely handled here
382 function UpdateRecentChanges($dbi, $pagename, $isnewpage) {
384 global $remoteuser; // this is set in the config
386 global $WikiPageStore;
388 $recentchanges = RetrievePage($dbi, gettext ("RecentChanges"),
391 // this shouldn't be necessary, since PhpWiki loads
392 // default pages if this is a new baby Wiki
393 if ($recentchanges == -1) {
394 $recentchanges = array();
398 $today = date($dateformat, $now);
400 if (date($dateformat, $recentchanges["lastmodified"]) != $today) {
402 $recentchanges["lastmodified"] = $now;
407 $numlines = sizeof($recentchanges["content"]);
411 // scroll through the page to the first date and break
412 // dates are marked with "____" at the beginning of the line
413 for ($i = 0; $i < $numlines; $i++) {
414 if (preg_match("/^____/",
415 $recentchanges["content"][$i])) {
418 $newpage[$k++] = $recentchanges["content"][$i];
422 // if it's a new date, insert it, else add the updated page's
425 $newpage[$k++] = $isNewDay ? "____$today\r"
426 : $recentchanges["content"][$i++];
428 $newpage[$k++] = "* [$pagename] (new) ..... $remoteuser\r";
430 $diffurl = "phpwiki:?diff=" . rawurlencode($pagename);
431 $newpage[$k++] = "* [$pagename] ([diff|$diffurl]) ..... $remoteuser\r";
434 $newpage[$k++] = "\r";
436 // copy the rest of the page into the new array
437 $pagename = preg_quote($pagename);
438 for (; $i < $numlines; $i++) {
439 // skip previous entry for $pagename
440 if (preg_match("|\[$pagename\]|", $recentchanges["content"][$i])) {
443 $newpage[$k++] = $recentchanges["content"][$i];
447 $recentchanges["content"] = $newpage;
449 InsertPage($dbi, gettext ("RecentChanges"), $recentchanges);
454 function ParseAndLink($bracketlink) {
455 global $dbi, $ScriptUrl, $AllowedProtocols, $InlineImages;
457 // $bracketlink will start and end with brackets; in between
458 // will be either a page name, a URL or both separated by a pipe.
460 // strip brackets and leading space
461 preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
462 // match the contents
463 preg_match("/([^|]+)(\|)?([^|]+)?/", $match[2], $matches);
465 if (isset($matches[3])) {
466 // named link of the form "[some link name | http://blippy.com/]"
467 $URL = trim($matches[3]);
468 $linkname = htmlspecialchars(trim($matches[1]));
471 // unnamed link of the form "[http://blippy.com/] or [wiki page]"
472 $URL = trim($matches[1]);
474 $linktype = 'simple';
477 if (IsWikiPage($dbi, $URL)) {
478 $link['type'] = "wiki-$linktype";
479 $link['link'] = LinkExistingWikiWord($URL, $linkname);
480 } elseif (preg_match("#^($AllowedProtocols):#", $URL)) {
481 // if it's an image, embed it; otherwise, it's a regular link
482 if (preg_match("/($InlineImages)$/i", $URL)) {
483 $link['type'] = "image-$linktype";
484 $link['link'] = LinkImage($URL, $linkname);
486 $link['type'] = "url-$linktype";
487 $link['link'] = LinkURL($URL, $linkname);
489 } elseif (preg_match("#^phpwiki:(.*)#", $URL, $match)) {
490 $link['type'] = "url-wiki-$linktype";
492 $linkname = htmlspecialchars($URL);
493 $link['link'] = "<a href=\"$ScriptUrl$match[1]\">$linkname</a>";
495 $link['type'] = "wiki-unknown-$linktype";
496 $link['link'] = LinkUnknownWikiWord($URL, $linkname);
503 function ExtractWikiPageLinks($content)
505 global $WikiNameRegexp;
507 $wikilinks = array();
508 $numlines = count($content);
509 for($l = 0; $l < $numlines; $l++)
511 $line = str_replace('[[', ' ', $content[$l]); // remove escaped '['
512 $numBracketLinks = preg_match_all("/\[\s*([^\]|]+\|)?\s*(.+?)\s*\]/", $line, $brktlinks);
513 for ($i = 0; $i < $numBracketLinks; $i++) {
514 $link = ParseAndLink($brktlinks[0][$i]);
515 if (preg_match("#^wiki#", $link['type']))
516 $wikilinks[$brktlinks[2][$i]] = 1;
518 $brktlink = preg_quote($brktlinks[0][$i]);
519 $line = preg_replace("|$brktlink|", '', $line);
522 if (preg_match_all("/!?$WikiNameRegexp/", $line, $link)) {
523 for ($i = 0; isset($link[0][$i]); $i++) {
524 if($link[0][$i][0] <> '!')
525 $wikilinks[$link[0][$i]] = 1;