2 rcs_id('$Id: stdlib.php,v 1.9 2000-11-08 15:40:00 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 _dotoken("R$i", $hash['refs'][$i], $page);
163 _dotoken('CONTENT', $content, $page);
168 function LinkExistingWikiWord($wikiword) {
170 $enc_word = rawurlencode($wikiword);
171 $wikiword = htmlspecialchars($wikiword);
172 return "<a href=\"$ScriptUrl?$enc_word\">$wikiword</a>";
175 function LinkUnknownWikiWord($wikiword) {
177 $enc_word = rawurlencode($wikiword);
178 $wikiword = htmlspecialchars($wikiword);
179 return "<u>$wikiword</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
182 function LinkURL($url) {
184 if(ereg("[<>\"]", $url)) {
185 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
187 $enc_url = htmlspecialchars($url);
188 return "<a href=\"$url\">$enc_url</a>";
192 function LinkImage($url, $alt="[External Image]") {
194 if(ereg("[<>\"]", $url)) {
195 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
197 return "<img src=\"$url\" ALT=\"$alt\">";
201 function RenderQuickSearch($value = "") {
203 return "<form action=\"$ScriptUrl\">\n" .
204 "<input type=text size=30 name=search value=\"$value\">\n" .
205 "<input type=submit value=\"". gettext("Search") .
209 function RenderFullSearch($value = "") {
211 return "<form action=\"$ScriptUrl\">\n" .
212 "<input type=text size=30 name=full value=\"$value\">\n" .
213 "<input type=submit value=\"". gettext("Search") .
217 function RenderMostPopular() {
218 global $ScriptUrl, $dbi;
220 $query = InitMostPopular($dbi, MOST_POPULAR_LIST_LENGTH);
222 while ($qhash = MostPopularNextMatch($dbi, $query)) {
223 $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
225 $result .= "</DL>\n";
230 function ParseAdminTokens($line) {
233 while (preg_match("/%%ADMIN-INPUT-(.*?)-(\w+)%%/", $line, $matches)) {
234 $head = str_replace("_", " ", $matches[2]);
235 $form = "<FORM ACTION=\"$ScriptUrl\" METHOD=POST>"
236 ."$head: <INPUT NAME=$matches[1] SIZE=20> "
237 ."<INPUT TYPE=SUBMIT VALUE=\"" . gettext("Go") . "\">"
239 $line = str_replace($matches[0], $form, $line);
244 // converts spaces to tabs
245 function CookSpaces($pagearray) {
246 return preg_replace("/ {3,8}/", "\t", $pagearray);
251 var $items = array();
254 function push($item) {
255 $this->items[$this->size] = $item;
261 if ($this->size == 0) {
262 return false; // stack is empty
265 return $this->items[$this->size];
274 return $this->items[$this->size - 1];
280 // end class definition
283 // I couldn't move this to lib/config.php because it
284 // wasn't declared yet.
288 Wiki HTML output can, at any given time, be in only one mode.
289 It will be something like Unordered List, Preformatted Text,
290 plain text etc. When we change modes we have to issue close tags
291 for one mode and start tags for another.
294 function SetHTMLOutputMode($tag, $tagdepth, $tabcount) {
298 if ($tagdepth == SINGLE_DEPTH) {
299 if ($tabcount < $stack->cnt()) {
300 // there are fewer tabs than stack,
301 // reduce stack to that tab count
302 while ($stack->cnt() > $tabcount) {
303 $closetag = $stack->pop();
304 if ($closetag == false) {
305 //echo "bounds error in tag stack";
308 $retvar .= "</$closetag>\n";
311 // if list type isn't the same,
312 // back up one more and push new tag
313 if ($tag != $stack->top()) {
314 $closetag = $stack->pop();
315 $retvar .= "</$closetag><$tag>\n";
319 } elseif ($tabcount > $stack->cnt()) {
320 // we add the diff to the stack
321 // stack might be zero
322 while ($stack->cnt() < $tabcount) {
324 $retvar .= "<$tag>\n";
326 if ($stack->cnt() > 10) {
327 // arbitrarily limit tag nesting
328 ExitWiki(gettext ("Stack bounds exceeded in SetHTMLOutputMode"));
333 if ($tag == $stack->top()) {
336 $closetag = $stack->pop();
337 #echo "</$closetag>\n";
339 $retvar .= "</$closetag>\n";
340 $retvar .= "<$tag>\n";
345 } elseif ($tagdepth == ZERO_DEPTH) {
346 // empty the stack for $depth == 0;
347 // what if the stack is empty?
348 if ($tag == $stack->top()) {
351 while ($stack->cnt() > 0) {
352 $closetag = $stack->pop();
353 #echo "</$closetag>\n";
354 $retvar .= "</$closetag>\n";
359 $retvar .= "<$tag>\n";
365 ExitWiki ("Passed bad tag depth value in SetHTMLOutputMode");
371 // end SetHTMLOutputMode
375 // The Recent Changes file is solely handled here
376 function UpdateRecentChanges($dbi, $pagename, $isnewpage) {
378 global $remoteuser; // this is set in the config
380 global $WikiPageStore;
382 $recentchanges = RetrievePage($dbi, gettext ("RecentChanges"),
385 // this shouldn't be necessary, since PhpWiki loads
386 // default pages if this is a new baby Wiki
387 if ($recentchanges == -1) {
388 $recentchanges = array();
392 $today = date($dateformat, $now);
394 if (date($dateformat, $recentchanges["lastmodified"]) != $today) {
396 $recentchanges["lastmodified"] = $now;
401 $numlines = sizeof($recentchanges["content"]);
405 // scroll through the page to the first date and break
406 // dates are marked with "____" at the beginning of the line
407 for ($i = 0; $i < ($numlines + 1); $i++) {
408 if (preg_match("/^____/",
409 $recentchanges["content"][$i])) {
412 $newpage[$k++] = $recentchanges["content"][$i];
416 // if it's a new date, insert it, else add the updated page's
420 $newpage[$k++] = "____$today\r";
421 $newpage[$k++] = "\r";
423 $newpage[$k++] = $recentchanges["content"][$i++];
426 $newpage[$k++] = "* [$pagename] (new) ..... $remoteuser\r";
428 $diffurl = "phpwiki:?diff=" . rawurlencode($pagename);
429 $newpage[$k++] = "* [$pagename] ([diff|$diffurl]) ..... $remoteuser\r";
432 // copy the rest of the page into the new array
433 $pagename = preg_quote($pagename);
434 for (; $i < $numlines; $i++) {
435 // skip previous entry for $pagename
436 if (preg_match("|\[$pagename\]|", $recentchanges["content"][$i])) {
439 $newpage[$k++] = $recentchanges["content"][$i];
443 $recentchanges["content"] = $newpage;
445 InsertPage($dbi, gettext ("RecentChanges"), $recentchanges);
450 function ParseAndLink($bracketlink) {
451 global $dbi, $ScriptUrl, $AllowedProtocols, $InlineImages;
453 // $bracketlink will start and end with brackets; in between
454 // will be either a page name, a URL or both separated by a pipe.
456 // strip brackets and leading space
457 preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
458 // match the contents
459 preg_match("/([^|]+)(\|)?([^|]+)?/", $match[2], $matches);
461 // if $matches[3] is set, this is a link in the form of:
462 // [some link name | http://blippy.com/]
464 if (isset($matches[3])) {
465 $URL = trim($matches[3]);
466 $linkname = htmlspecialchars(trim($matches[1]));
467 // assert proper URL's
468 if (preg_match("#^($AllowedProtocols):#", $URL)) {
469 if (preg_match("/($InlineImages)$/i", $URL)) {
470 $link['type'] = 'image-named';
471 $link['link'] = LinkImage($URL, $linkname);
473 $link['type'] = 'url-named';
474 $link['link'] = "<a href=\"$URL\">$linkname</a>";
476 } elseif (preg_match("#^phpwiki:(.*)#", $URL, $match)) {
477 $link['type'] = 'url-wiki-named';
478 $link['link'] = "<a href=\"$ScriptUrl$match[1]\">$linkname</a>";
480 $link['type'] = 'url-bad';
481 $link['link'] = "<b><u>BAD URL -- links have to start with one" .
482 "of $AllowedProtocols followed by ':'</u></b>";
488 // otherwise this is just a Wiki page like this: [page name]
489 // or a URL in brackets: [http://foo.com/]
491 if (isset($matches[1])) {
492 $linkname = trim($matches[1]);
493 if (IsWikiPage($dbi, $linkname)) {
494 $link['type'] = 'wiki';
495 $link['link'] = LinkExistingWikiWord($linkname);
496 } elseif (preg_match("#^($AllowedProtocols):#", $linkname)) {
497 // if it's an image, embed it; otherwise, it's a regular link
498 if (preg_match("/($InlineImages)$/i", $linkname)) {
499 $link['type'] = 'image-simple';
500 $link['link'] = LinkImage($linkname);
502 $link['type'] = 'url-simple';
503 $link['link'] = LinkURL($linkname);
506 $link['type'] = 'wiki-unknown';
507 $link['link'] = LinkUnknownWikiWord($linkname);
512 $link['type'] = 'unknown';
513 $link['link'] = $bracketlink;
518 function ExtractWikiPageLinks($content)
520 global $WikiNameRegexp;
522 $wikilinks = array();
523 $numlines = count($content);
524 for($l = 0; $l < $numlines; $l++)
526 $line = $content[$l];
527 $numBracketLinks = preg_match_all("/\[\s*(.+?)\s*\]/", $line, $brktlinks);
528 for ($i = 0; $i < $numBracketLinks; $i++) {
529 $link = ParseAndLink($brktlinks[0][$i]);
530 if($link['type'] == 'wiki' || $link['type'] == 'wiki-unknown')
531 $wikilinks[$brktlinks[1][$i]] = 1;
533 $brktlink = preg_quote($brktlinks[0][$i]);
534 $line = preg_replace("|$brktlink|", '', $line);
537 if (preg_match_all("/!?$WikiNameRegexp/", $line, $link)) {
538 for ($i = 0; isset($link[0][$i]); $i++) {
539 if($link[0][$i][0] <> '!')
540 $wikilinks[$link[0][$i]] = 1;