1 <!-- $Id: stdlib.php,v 1.8 2000-11-01 11:31:41 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 $page = join('', file($templates[$template]));
96 $page = str_replace('###', "#$FieldSeparator#", $page);
98 // valid for all pagetypes
99 $page = str_replace("#$FieldSeparator#SCRIPTURL#$FieldSeparator#",
101 $page = str_replace("#$FieldSeparator#PAGE#$FieldSeparator#",
102 htmlspecialchars($name), $page);
103 $page = str_replace("#$FieldSeparator#ALLOWEDPROTOCOLS#$FieldSeparator#",
104 $AllowedProtocols, $page);
105 $page = str_replace("#$FieldSeparator#LOGO#$FieldSeparator#",
108 // invalid for messages (search results, error messages)
109 if ($template != 'MESSAGE') {
110 $page = str_replace("#$FieldSeparator#PAGEURL#$FieldSeparator#",
111 rawurlencode($name), $page);
112 $page = str_replace("#$FieldSeparator#LASTMODIFIED#$FieldSeparator#",
113 date($datetimeformat, $hash['lastmodified']), $page);
114 $page = str_replace("#$FieldSeparator#LASTAUTHOR#$FieldSeparator#",
115 $hash['author'], $page);
116 $page = str_replace("#$FieldSeparator#VERSION#$FieldSeparator#",
117 $hash['version'], $page);
118 if (strstr($page, "#$FieldSeparator#HITS#$FieldSeparator#")) {
119 $page = str_replace("#$FieldSeparator#HITS#$FieldSeparator#",
120 GetHitCount($dbi, $name), $page);
122 if (strstr($page, "#$FieldSeparator#RELATEDPAGES#$FieldSeparator#")) {
123 $page = str_replace("#$FieldSeparator#RELATEDPAGES#$FieldSeparator#",
124 LinkRelatedPages($dbi, $name), $page);
128 // valid only for EditLinks
129 if ($template == 'EDITLINKS') {
130 for ($i = 1; $i <= NUM_LINKS; $i++)
131 $page = str_replace("#$FieldSeparator#R$i#$FieldSeparator#",
132 $hash['refs'][$i], $page);
135 if (isset($hash['copy'])) {
136 $page = str_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#",
139 $page = ereg_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#[^\n]*",
143 $page = str_replace("#$FieldSeparator#CONTENT#$FieldSeparator#",
149 function LinkExistingWikiWord($wikiword) {
151 $enc_word = rawurlencode($wikiword);
152 $wikiword = htmlspecialchars($wikiword);
153 return "<a href=\"$ScriptUrl?$enc_word\">$wikiword</a>";
156 function LinkUnknownWikiWord($wikiword) {
158 $enc_word = rawurlencode($wikiword);
159 $wikiword = htmlspecialchars($wikiword);
160 return "<u>$wikiword</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
163 function LinkURL($url) {
165 if(ereg("[<>\"]", $url)) {
166 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
168 $enc_url = htmlspecialchars($url);
169 return "<a href=\"$url\">$enc_url</a>";
173 function LinkImage($url, $alt="[External Image]") {
175 if(ereg("[<>\"]", $url)) {
176 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
178 return "<img src=\"$url\" ALT=\"$alt\">";
182 function RenderQuickSearch($value = "") {
184 return "<form action=\"$ScriptUrl\">\n" .
185 "<input type=text size=30 name=search value=\"$value\">\n" .
186 "<input type=submit value=\"". gettext("Search") .
190 function RenderFullSearch($value = "") {
192 return "<form action=\"$ScriptUrl\">\n" .
193 "<input type=text size=30 name=full value=\"$value\">\n" .
194 "<input type=submit value=\"". gettext("Search") .
198 function RenderMostPopular() {
199 global $ScriptUrl, $dbi;
201 $query = InitMostPopular($dbi, MOST_POPULAR_LIST_LENGTH);
203 while ($qhash = MostPopularNextMatch($dbi, $query)) {
204 $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
206 $result .= "</DL>\n";
211 // converts spaces to tabs
212 function CookSpaces($pagearray) {
213 return preg_replace("/ {3,8}/", "\t", $pagearray);
218 var $items = array();
221 function push($item) {
222 $this->items[$this->size] = $item;
228 if ($this->size == 0) {
229 return false; // stack is empty
232 return $this->items[$this->size];
241 return $this->items[$this->size - 1];
247 // end class definition
250 // I couldn't move this to lib/config.php because it
251 // wasn't declared yet.
255 Wiki HTML output can, at any given time, be in only one mode.
256 It will be something like Unordered List, Preformatted Text,
257 plain text etc. When we change modes we have to issue close tags
258 for one mode and start tags for another.
261 function SetHTMLOutputMode($tag, $tagdepth, $tabcount) {
265 if ($tagdepth == SINGLE_DEPTH) {
266 if ($tabcount < $stack->cnt()) {
267 // there are fewer tabs than stack,
268 // reduce stack to that tab count
269 while ($stack->cnt() > $tabcount) {
270 $closetag = $stack->pop();
271 if ($closetag == false) {
272 //echo "bounds error in tag stack";
275 $retvar .= "</$closetag>\n";
278 // if list type isn't the same,
279 // back up one more and push new tag
280 if ($tag != $stack->top()) {
281 $closetag = $stack->pop();
282 $retvar .= "</$closetag><$tag>\n";
286 } elseif ($tabcount > $stack->cnt()) {
287 // we add the diff to the stack
288 // stack might be zero
289 while ($stack->cnt() < $tabcount) {
291 $retvar .= "<$tag>\n";
293 if ($stack->cnt() > 10) {
294 // arbitrarily limit tag nesting
295 ExitWiki(gettext ("Stack bounds exceeded in SetHTMLOutputMode"));
300 if ($tag == $stack->top()) {
303 $closetag = $stack->pop();
304 #echo "</$closetag>\n";
306 $retvar .= "</$closetag>\n";
307 $retvar .= "<$tag>\n";
312 } elseif ($tagdepth == ZERO_DEPTH) {
313 // empty the stack for $depth == 0;
314 // what if the stack is empty?
315 if ($tag == $stack->top()) {
318 while ($stack->cnt() > 0) {
319 $closetag = $stack->pop();
320 #echo "</$closetag>\n";
321 $retvar .= "</$closetag>\n";
326 $retvar .= "<$tag>\n";
332 ExitWiki ("Passed bad tag depth value in SetHTMLOutputMode");
338 // end SetHTMLOutputMode
342 // The Recent Changes file is solely handled here
343 function UpdateRecentChanges($dbi, $pagename, $isnewpage) {
345 global $remoteuser; // this is set in the config
347 global $WikiPageStore;
349 $recentchanges = RetrievePage($dbi, gettext ("RecentChanges"),
352 // this shouldn't be necessary, since PhpWiki loads
353 // default pages if this is a new baby Wiki
354 if ($recentchanges == -1) {
355 $recentchanges = array();
359 $today = date($dateformat, $now);
361 if (date($dateformat, $recentchanges["lastmodified"]) != $today) {
363 $recentchanges["lastmodified"] = $now;
368 $numlines = sizeof($recentchanges["content"]);
372 // scroll through the page to the first date and break
373 // dates are marked with "____" at the beginning of the line
374 for ($i = 0; $i < ($numlines + 1); $i++) {
375 if (preg_match("/^____/",
376 $recentchanges["content"][$i])) {
379 $newpage[$k++] = $recentchanges["content"][$i];
383 // if it's a new date, insert it, else add the updated page's
387 $newpage[$k++] = "____$today\r";
388 $newpage[$k++] = "\r";
390 $newpage[$k++] = $recentchanges["content"][$i++];
393 $newpage[$k++] = "* [$pagename] (new) ..... $remoteuser\r";
395 $diffurl = "phpwiki:?diff=" . rawurlencode($pagename);
396 $newpage[$k++] = "* [$pagename] ([diff|$diffurl]) ..... $remoteuser\r";
399 // copy the rest of the page into the new array
400 $pagename = preg_quote($pagename);
401 for (; $i < $numlines; $i++) {
402 // skip previous entry for $pagename
403 if (preg_match("|\[$pagename\]|", $recentchanges["content"][$i])) {
406 $newpage[$k++] = $recentchanges["content"][$i];
410 $recentchanges["content"] = $newpage;
412 InsertPage($dbi, gettext ("RecentChanges"), $recentchanges);
417 function ParseAndLink($bracketlink) {
418 global $dbi, $ScriptUrl, $AllowedProtocols, $InlineImages;
420 // $bracketlink will start and end with brackets; in between
421 // will be either a page name, a URL or both separated by a pipe.
423 // strip brackets and leading space
424 preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
425 // match the contents
426 preg_match("/([^|]+)(\|)?([^|]+)?/", $match[2], $matches);
428 // if $matches[3] is set, this is a link in the form of:
429 // [some link name | http://blippy.com/]
431 if (isset($matches[3])) {
432 $URL = trim($matches[3]);
433 $linkname = htmlspecialchars(trim($matches[1]));
434 // assert proper URL's
435 if (preg_match("#^($AllowedProtocols):#", $URL)) {
436 if (preg_match("/($InlineImages)$/i", $URL)) {
437 $link['type'] = 'image-named';
438 $link['link'] = LinkImage($URL, $linkname);
440 $link['type'] = 'url-named';
441 $link['link'] = "<a href=\"$URL\">$linkname</a>";
443 } elseif (preg_match("#^phpwiki:(.*)#", $URL, $match)) {
444 $link['type'] = 'url-wiki-named';
445 $link['link'] = "<a href=\"$ScriptUrl$match[1]\">$linkname</a>";
447 $link['type'] = 'url-bad';
448 $link['link'] = "<b><u>BAD URL -- links have to start with one" .
449 "of $AllowedProtocols followed by ':'</u></b>";
455 // otherwise this is just a Wiki page like this: [page name]
456 // or a URL in brackets: [http://foo.com/]
458 if (isset($matches[1])) {
459 $linkname = trim($matches[1]);
460 if (IsWikiPage($dbi, $linkname)) {
461 $link['type'] = 'wiki';
462 $link['link'] = LinkExistingWikiWord($linkname);
463 } elseif (preg_match("#^($AllowedProtocols):#", $linkname)) {
464 // if it's an image, embed it; otherwise, it's a regular link
465 if (preg_match("/($InlineImages)$/i", $linkname)) {
466 $link['type'] = 'image-simple';
467 $link['link'] = LinkImage($linkname);
469 $link['type'] = 'url-simple';
470 $link['link'] = LinkURL($linkname);
473 $link['type'] = 'wiki-unknown';
474 $link['link'] = LinkUnknownWikiWord($linkname);
479 $link['type'] = 'unknown';
480 $link['link'] = $bracketlink;
485 function ExtractWikiPageLinks($content)
487 global $WikiNameRegexp;
489 $wikilinks = array();
490 $numlines = count($content);
491 for($l = 0; $l < $numlines; $l++)
493 $line = $content[$l];
494 $numBracketLinks = preg_match_all("/\[\s*(.+?)\s*\]/", $line, $brktlinks);
495 for ($i = 0; $i < $numBracketLinks; $i++) {
496 $link = ParseAndLink($brktlinks[0][$i]);
497 if($link['type'] == 'wiki' || $link['type'] == 'wiki-unknown')
498 $wikilinks[$brktlinks[1][$i]] = 1;
500 $brktlink = preg_quote($brktlinks[0][$i]);
501 $line = preg_replace("|$brktlink|", '', $line);
504 if (preg_match_all("/!?$WikiNameRegexp/", $line, $link)) {
505 for ($i = 0; isset($link[0][$i]); $i++) {
506 if($link[0][$i][0] <> '!')
507 $wikilinks[$link[0][$i]] = 1;