1 <!-- $Id: stdlib.php,v 1.2 2000-10-19 21:36:50 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)
23 function LinkRelatedPages($dbi, $pagename)
25 // currently not supported everywhere
26 if(!function_exists('GetWikiPageLinks'))
29 $links = GetWikiPageLinks($dbi, $pagename);
31 $txt = "<b>" . NUM_RELATED_PAGES . " best incoming links:</b>\n";
32 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
33 if(isset($links['in'][$i])) {
34 list($name, $score) = $links['in'][$i];
35 $txt .= LinkExistingWikiWord($name) . " ($score), ";
39 $txt .= "\n<br><b>" . NUM_RELATED_PAGES . " best outgoing links:</b>\n";
40 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
41 if(isset($links['out'][$i])) {
42 list($name, $score) = $links['out'][$i];
43 if(IsWikiPage($dbi, $name))
44 $txt .= LinkExistingWikiWord($name) . " ($score), ";
48 $txt .= "\n<br><b>" . NUM_RELATED_PAGES . " most popular nearby:</b>\n";
49 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
50 if(isset($links['popular'][$i])) {
51 list($name, $score) = $links['popular'][$i];
52 $txt .= LinkExistingWikiWord($name) . " ($score), ";
60 function GeneratePage($template, $content, $name, $hash)
62 global $ScriptUrl, $AllowedProtocols, $templates;
63 global $datetimeformat, $dbi, $logo;
68 $page = join('', file($templates[$template]));
69 $page = str_replace('###', "#$FieldSeparator#", $page);
71 // valid for all pagetypes
72 $page = str_replace("#$FieldSeparator#SCRIPTURL#$FieldSeparator#",
74 $page = str_replace("#$FieldSeparator#PAGE#$FieldSeparator#",
75 htmlspecialchars($name), $page);
76 $page = str_replace("#$FieldSeparator#ALLOWEDPROTOCOLS#$FieldSeparator#",
77 $AllowedProtocols, $page);
78 $page = str_replace("#$FieldSeparator#LOGO#$FieldSeparator#",
81 // invalid for messages (search results, error messages)
82 if ($template != 'MESSAGE') {
83 $page = str_replace("#$FieldSeparator#PAGEURL#$FieldSeparator#",
84 rawurlencode($name), $page);
85 $page = str_replace("#$FieldSeparator#LASTMODIFIED#$FieldSeparator#",
86 date($datetimeformat, $hash['lastmodified']), $page);
87 $page = str_replace("#$FieldSeparator#LASTAUTHOR#$FieldSeparator#",
88 $hash['author'], $page);
89 $page = str_replace("#$FieldSeparator#VERSION#$FieldSeparator#",
90 $hash['version'], $page);
91 if (strstr($page, "#$FieldSeparator#HITS#$FieldSeparator#")) {
92 $page = str_replace("#$FieldSeparator#HITS#$FieldSeparator#",
93 GetHitCount($dbi, $name), $page);
95 if (strstr($page, "#$FieldSeparator#RELATEDPAGES#$FieldSeparator#")) {
96 $page = str_replace("#$FieldSeparator#RELATEDPAGES#$FieldSeparator#",
97 LinkRelatedPages($dbi, $name), $page);
101 // valid only for EditLinks
102 if ($template == 'EDITLINKS') {
103 for ($i = 1; $i <= NUM_LINKS; $i++)
104 $page = str_replace("#$FieldSeparator#R$i#$FieldSeparator#",
105 $hash['refs'][$i], $page);
109 $page = str_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#",
112 $page = ereg_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#[^\n]*",
116 $page = str_replace("#$FieldSeparator#CONTENT#$FieldSeparator#",
122 function LinkExistingWikiWord($wikiword) {
124 $enc_word = rawurlencode($wikiword);
125 $wikiword = htmlspecialchars($wikiword);
126 return "<a href=\"$ScriptUrl?$enc_word\">$wikiword</a>";
129 function LinkUnknownWikiWord($wikiword) {
131 $enc_word = rawurlencode($wikiword);
132 $wikiword = htmlspecialchars($wikiword);
133 return "<u>$wikiword</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
136 function LinkURL($url) {
138 if(ereg("[<>\"]", $url)) {
139 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
141 $enc_url = htmlspecialchars($url);
142 return "<a href=\"$url\">$enc_url</a>";
146 function LinkImage($url) {
148 if(ereg("[<>\"]", $url)) {
149 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
151 return "<img src=\"$url\">";
155 function RenderQuickSearch() {
156 global $value, $ScriptUrl;
157 $formtext = "<form action='$ScriptUrl'>\n<input type='text' size='40' name='search' value='$value'>\n</form>\n";
161 function RenderFullSearch() {
162 global $value, $ScriptUrl;
163 $formtext = "<form action='$ScriptUrl'>\n<input type='text' size='40' name='full' value='$value'>\n</form>\n";
167 function RenderMostPopular() {
168 global $ScriptUrl, $dbi;
170 $query = InitMostPopular($dbi, MOST_POPULAR_LIST_LENGTH);
172 while ($qhash = MostPopularNextMatch($dbi, $query)) {
173 $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
175 $result .= "</DL>\n";
180 // converts spaces to tabs
181 function CookSpaces($pagearray) {
182 return preg_replace("/ {3,8}/", "\t", $pagearray);
190 function push($item) {
191 $this->items[$this->size] = $item;
197 if ($this->size == 0) {
198 return false; // stack is empty
201 return $this->items[$this->size];
209 return $this->items[$this->size - 1];
213 // end class definition
216 // I couldn't move this to lib/config.php because it
217 // wasn't declared yet.
221 Wiki HTML output can, at any given time, be in only one mode.
222 It will be something like Unordered List, Preformatted Text,
223 plain text etc. When we change modes we have to issue close tags
224 for one mode and start tags for another.
227 function SetHTMLOutputMode($tag, $tagdepth, $tabcount) {
231 if ($tagdepth == SINGLE_DEPTH) {
232 if ($tabcount < $stack->cnt()) {
233 // there are fewer tabs than stack,
234 // reduce stack to that tab count
235 while ($stack->cnt() > $tabcount) {
236 $closetag = $stack->pop();
237 if ($closetag == false) {
238 //echo "bounds error in tag stack";
241 $retvar .= "</$closetag>\n";
244 // if list type isn't the same,
245 // back up one more and push new tag
246 if ($tag != $stack->top()) {
247 $closetag = $stack->pop();
248 $retvar .= "</$closetag><$tag>\n";
252 } elseif ($tabcount > $stack->cnt()) {
253 // we add the diff to the stack
254 // stack might be zero
255 while ($stack->cnt() < $tabcount) {
257 $retvar .= "<$tag>\n";
259 if ($stack->cnt() > 10) {
260 // arbitrarily limit tag nesting
261 echo "Stack bounds exceeded in SetHTMLOutputMode\n";
267 if ($tag == $stack->top()) {
270 $closetag = $stack->pop();
271 #echo "</$closetag>\n";
273 $retvar .= "</$closetag>\n";
274 $retvar .= "<$tag>\n";
279 } elseif ($tagdepth == ZERO_DEPTH) {
280 // empty the stack for $depth == 0;
281 // what if the stack is empty?
282 if ($tag == $stack->top()) {
285 while ($stack->cnt() > 0) {
286 $closetag = $stack->pop();
287 #echo "</$closetag>\n";
288 $retvar .= "</$closetag>\n";
293 $retvar .= "<$tag>\n";
299 echo "Passed bad tag depth value in SetHTMLOutputMode\n";
306 // end SetHTMLOutputMode
310 // The Recent Changes file is solely handled here
311 function UpdateRecentChanges($dbi, $pagename, $isnewpage) {
313 global $remoteuser; // this is set in the config
316 global $WikiPageStore;
318 $recentchanges = RetrievePage($dbi, gettext("RecentChanges"), $WikiPageStore);
320 // this shouldn't be necessary, since PhpWiki loads
321 // default pages if this is a new baby Wiki
322 if ($recentchanges == -1) {
323 $recentchanges = array();
327 $today = date($dateformat, $now);
329 if (date($dateformat, $recentchanges["lastmodified"]) != $today) {
331 $recentchanges["lastmodified"] = $now;
336 $numlines = sizeof($recentchanges["content"]);
340 // scroll through the page to the first date and break
341 // dates are marked with "____" at the beginning of the line
342 for ($i = 0; $i < ($numlines + 1); $i++) {
343 if (preg_match("/^____/",
344 $recentchanges["content"][$i])) {
347 $newpage[$k++] = $recentchanges["content"][$i];
351 // if it's a new date, insert it, else add the updated page's
355 $newpage[$k++] = "____$today\r";
356 $newpage[$k++] = "\r";
358 $newpage[$k++] = $recentchanges["content"][$i++];
361 $newpage[$k++] = "\t* [$pagename] (new) ..... $remoteuser\r";
363 $diffurl = "$ScriptUrl?diff=" . rawurlencode($pagename);
364 $newpage[$k++] = "\t* [$pagename] ([diff|$diffurl]) ..... $remoteuser\r";
367 // copy the rest of the page into the new array
368 $pagename = preg_quote($pagename);
369 for (; $i < ($numlines + 1); $i++) {
370 // skip previous entry for $pagename
371 if (preg_match("|\[$pagename\]|", $recentchanges["content"][$i])) {
374 $newpage[$k++] = $recentchanges["content"][$i];
378 $recentchanges["content"] = $newpage;
380 InsertPage($dbi, gettext("RecentChanges"), $recentchanges);
385 function ParseAndLink($bracketlink) {
386 global $dbi, $AllowedProtocols;
388 // $bracketlink will start and end with brackets; in between
389 // will be either a page name, a URL or both separated by a pipe.
391 // strip brackets and leading space
392 preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
393 $linkdata = $match[2];
395 // send back links that are only numbers (they are references)
396 if (preg_match("/^\d+$/", $linkdata)) {
397 $link['type'] = 'ref';
398 $link['link'] = $bracketlink;
402 // send back escaped ([[) bracket sets
403 if (preg_match("/^\[/", $linkdata)) {
404 $link['type'] = 'none';
405 $link['link'] = htmlspecialchars(substr($bracketlink, 1));
409 // match the contents
410 preg_match("/([^|]+)(\|)?([^|]+)?/", $linkdata, $matches);
413 // if $matches[3] is set, this is a link in the form of:
414 // [some link name | http://blippy.com/]
416 if (isset($matches[3])) {
417 $URL = trim($matches[3]);
418 $linkname = htmlspecialchars(trim($matches[1]));
419 // assert proper URL's
420 if (preg_match("#^($AllowedProtocols):#", $URL)) {
421 $link['type'] = 'url-named';
422 $link['link'] = "<a href=\"$URL\">$linkname</a>";
424 $link['type'] = 'url-bad';
425 $link['link'] = "<b><u>BAD URL -- links have to start with one" .
426 "of $AllowedProtocols followed by ':'</u></b>";
432 // otherwise this is just a Wiki page like this: [page name]
433 // or a URL in brackets: [http://foo.com/]
435 if (isset($matches[1])) {
436 $linkname = trim($matches[1]);
437 if (IsWikiPage($dbi, $linkname)) {
438 $link['type'] = 'wiki';
439 $link['link'] = LinkExistingWikiWord($linkname);
440 } elseif (preg_match("#^($AllowedProtocols):#", $linkname)) {
441 // if it's an image, embed it; otherwise, it's a regular link
442 if (preg_match("/jpg$|png$|gif$/i", $linkname)) {
443 $link['type'] = 'url-image';
444 $link['link'] = LinkImage($linkname);
446 $link['type'] = 'url-simple';
447 $link['link'] = LinkURL($linkname);
450 $link['type'] = 'wiki-unknown';
451 $link['link'] = LinkUnknownWikiWord($linkname);
458 $link['type'] = 'unknown';
459 $link['link'] = $bracketlink;
464 function ExtractWikiPageLinks($content)
466 $wikilinks = array();
468 $numlines = count($content);
469 for($l = 0; $l < $numlines; $l++)
471 $line = $content[$l];
472 $numBracketLinks = preg_match_all("/\[\s*(.+?)\s*\]/", $line, $brktlinks);
473 for ($i = 0; $i < $numBracketLinks; $i++) {
474 $link = ParseAndLink($brktlinks[0][$i]);
475 if($link['type'] == 'wiki' || $link['type'] == 'wiki-unknown')
476 $wikilinks[$brktlinks[1][$i]]++;
478 $brktlink = preg_quote($brktlinks[0][$i]);
479 $line = preg_replace("|$brktlink|", '', $line);
482 if (preg_match_all("#!?\b(([A-Z][a-z]+){2,})\b#", $line, $link)) {
483 for ($i = 0; $link[0][$i]; $i++) {
484 if(!strstr($link[0][$i], '!'))
485 $wikilinks[$link[0][$i]]++;