1 <!-- $Id: stdlib.php,v 1.3 2000-10-19 22:25:45 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>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);
52 $txt = "<b>" . NUM_RELATED_PAGES . " best incoming links:</b>\n";
53 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
54 if(isset($links['in'][$i])) {
55 list($name, $score) = $links['in'][$i];
56 $txt .= LinkExistingWikiWord($name) . " ($score), ";
60 $txt .= "\n<br><b>" . NUM_RELATED_PAGES . " best outgoing links:</b>\n";
61 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
62 if(isset($links['out'][$i])) {
63 list($name, $score) = $links['out'][$i];
64 if(IsWikiPage($dbi, $name))
65 $txt .= LinkExistingWikiWord($name) . " ($score), ";
69 $txt .= "\n<br><b>" . NUM_RELATED_PAGES . " most popular nearby:</b>\n";
70 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
71 if(isset($links['popular'][$i])) {
72 list($name, $score) = $links['popular'][$i];
73 $txt .= LinkExistingWikiWord($name) . " ($score), ";
81 function GeneratePage($template, $content, $name, $hash)
83 global $ScriptUrl, $AllowedProtocols, $templates;
84 global $datetimeformat, $dbi, $logo;
89 $page = join('', file($templates[$template]));
90 $page = str_replace('###', "#$FieldSeparator#", $page);
92 // valid for all pagetypes
93 $page = str_replace("#$FieldSeparator#SCRIPTURL#$FieldSeparator#",
95 $page = str_replace("#$FieldSeparator#PAGE#$FieldSeparator#",
96 htmlspecialchars($name), $page);
97 $page = str_replace("#$FieldSeparator#ALLOWEDPROTOCOLS#$FieldSeparator#",
98 $AllowedProtocols, $page);
99 $page = str_replace("#$FieldSeparator#LOGO#$FieldSeparator#",
102 // invalid for messages (search results, error messages)
103 if ($template != 'MESSAGE') {
104 $page = str_replace("#$FieldSeparator#PAGEURL#$FieldSeparator#",
105 rawurlencode($name), $page);
106 $page = str_replace("#$FieldSeparator#LASTMODIFIED#$FieldSeparator#",
107 date($datetimeformat, $hash['lastmodified']), $page);
108 $page = str_replace("#$FieldSeparator#LASTAUTHOR#$FieldSeparator#",
109 $hash['author'], $page);
110 $page = str_replace("#$FieldSeparator#VERSION#$FieldSeparator#",
111 $hash['version'], $page);
112 if (strstr($page, "#$FieldSeparator#HITS#$FieldSeparator#")) {
113 $page = str_replace("#$FieldSeparator#HITS#$FieldSeparator#",
114 GetHitCount($dbi, $name), $page);
116 if (strstr($page, "#$FieldSeparator#RELATEDPAGES#$FieldSeparator#")) {
117 $page = str_replace("#$FieldSeparator#RELATEDPAGES#$FieldSeparator#",
118 LinkRelatedPages($dbi, $name), $page);
122 // valid only for EditLinks
123 if ($template == 'EDITLINKS') {
124 for ($i = 1; $i <= NUM_LINKS; $i++)
125 $page = str_replace("#$FieldSeparator#R$i#$FieldSeparator#",
126 $hash['refs'][$i], $page);
130 $page = str_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#",
133 $page = ereg_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#[^\n]*",
137 $page = str_replace("#$FieldSeparator#CONTENT#$FieldSeparator#",
143 function LinkExistingWikiWord($wikiword) {
145 $enc_word = rawurlencode($wikiword);
146 $wikiword = htmlspecialchars($wikiword);
147 return "<a href=\"$ScriptUrl?$enc_word\">$wikiword</a>";
150 function LinkUnknownWikiWord($wikiword) {
152 $enc_word = rawurlencode($wikiword);
153 $wikiword = htmlspecialchars($wikiword);
154 return "<u>$wikiword</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
157 function LinkURL($url) {
159 if(ereg("[<>\"]", $url)) {
160 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
162 $enc_url = htmlspecialchars($url);
163 return "<a href=\"$url\">$enc_url</a>";
167 function LinkImage($url) {
169 if(ereg("[<>\"]", $url)) {
170 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
172 return "<img src=\"$url\">";
176 function RenderQuickSearch() {
177 global $value, $ScriptUrl;
178 $formtext = "<form action='$ScriptUrl'>\n<input type='text' size='40' name='search' value='$value'>\n</form>\n";
182 function RenderFullSearch() {
183 global $value, $ScriptUrl;
184 $formtext = "<form action='$ScriptUrl'>\n<input type='text' size='40' name='full' value='$value'>\n</form>\n";
188 function RenderMostPopular() {
189 global $ScriptUrl, $dbi;
191 $query = InitMostPopular($dbi, MOST_POPULAR_LIST_LENGTH);
193 while ($qhash = MostPopularNextMatch($dbi, $query)) {
194 $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
196 $result .= "</DL>\n";
201 // converts spaces to tabs
202 function CookSpaces($pagearray) {
203 return preg_replace("/ {3,8}/", "\t", $pagearray);
211 function push($item) {
212 $this->items[$this->size] = $item;
218 if ($this->size == 0) {
219 return false; // stack is empty
222 return $this->items[$this->size];
230 return $this->items[$this->size - 1];
234 // end class definition
237 // I couldn't move this to lib/config.php because it
238 // wasn't declared yet.
242 Wiki HTML output can, at any given time, be in only one mode.
243 It will be something like Unordered List, Preformatted Text,
244 plain text etc. When we change modes we have to issue close tags
245 for one mode and start tags for another.
248 function SetHTMLOutputMode($tag, $tagdepth, $tabcount) {
252 if ($tagdepth == SINGLE_DEPTH) {
253 if ($tabcount < $stack->cnt()) {
254 // there are fewer tabs than stack,
255 // reduce stack to that tab count
256 while ($stack->cnt() > $tabcount) {
257 $closetag = $stack->pop();
258 if ($closetag == false) {
259 //echo "bounds error in tag stack";
262 $retvar .= "</$closetag>\n";
265 // if list type isn't the same,
266 // back up one more and push new tag
267 if ($tag != $stack->top()) {
268 $closetag = $stack->pop();
269 $retvar .= "</$closetag><$tag>\n";
273 } elseif ($tabcount > $stack->cnt()) {
274 // we add the diff to the stack
275 // stack might be zero
276 while ($stack->cnt() < $tabcount) {
278 $retvar .= "<$tag>\n";
280 if ($stack->cnt() > 10) {
281 // arbitrarily limit tag nesting
282 ExitWiki("Stack bounds exceeded in SetHTMLOutputMode");
287 if ($tag == $stack->top()) {
290 $closetag = $stack->pop();
291 #echo "</$closetag>\n";
293 $retvar .= "</$closetag>\n";
294 $retvar .= "<$tag>\n";
299 } elseif ($tagdepth == ZERO_DEPTH) {
300 // empty the stack for $depth == 0;
301 // what if the stack is empty?
302 if ($tag == $stack->top()) {
305 while ($stack->cnt() > 0) {
306 $closetag = $stack->pop();
307 #echo "</$closetag>\n";
308 $retvar .= "</$closetag>\n";
313 $retvar .= "<$tag>\n";
318 ExitWiki("Passed bad tag depth value in SetHTMLOutputMode");
324 // end SetHTMLOutputMode
328 // The Recent Changes file is solely handled here
329 function UpdateRecentChanges($dbi, $pagename, $isnewpage) {
331 global $remoteuser; // this is set in the config
334 global $WikiPageStore;
336 $recentchanges = RetrievePage($dbi, gettext("RecentChanges"), $WikiPageStore);
338 // this shouldn't be necessary, since PhpWiki loads
339 // default pages if this is a new baby Wiki
340 if ($recentchanges == -1) {
341 $recentchanges = array();
345 $today = date($dateformat, $now);
347 if (date($dateformat, $recentchanges["lastmodified"]) != $today) {
349 $recentchanges["lastmodified"] = $now;
354 $numlines = sizeof($recentchanges["content"]);
358 // scroll through the page to the first date and break
359 // dates are marked with "____" at the beginning of the line
360 for ($i = 0; $i < ($numlines + 1); $i++) {
361 if (preg_match("/^____/",
362 $recentchanges["content"][$i])) {
365 $newpage[$k++] = $recentchanges["content"][$i];
369 // if it's a new date, insert it, else add the updated page's
373 $newpage[$k++] = "____$today\r";
374 $newpage[$k++] = "\r";
376 $newpage[$k++] = $recentchanges["content"][$i++];
379 $newpage[$k++] = "\t* [$pagename] (new) ..... $remoteuser\r";
381 $diffurl = "$ScriptUrl?diff=" . rawurlencode($pagename);
382 $newpage[$k++] = "\t* [$pagename] ([diff|$diffurl]) ..... $remoteuser\r";
385 // copy the rest of the page into the new array
386 $pagename = preg_quote($pagename);
387 for (; $i < ($numlines + 1); $i++) {
388 // skip previous entry for $pagename
389 if (preg_match("|\[$pagename\]|", $recentchanges["content"][$i])) {
392 $newpage[$k++] = $recentchanges["content"][$i];
396 $recentchanges["content"] = $newpage;
398 InsertPage($dbi, gettext("RecentChanges"), $recentchanges);
403 function ParseAndLink($bracketlink) {
404 global $dbi, $AllowedProtocols;
406 // $bracketlink will start and end with brackets; in between
407 // will be either a page name, a URL or both separated by a pipe.
409 // strip brackets and leading space
410 preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
411 $linkdata = $match[2];
413 // send back links that are only numbers (they are references)
414 if (preg_match("/^\d+$/", $linkdata)) {
415 $link['type'] = 'ref';
416 $link['link'] = $bracketlink;
420 // send back escaped ([[) bracket sets
421 if (preg_match("/^\[/", $linkdata)) {
422 $link['type'] = 'none';
423 $link['link'] = htmlspecialchars(substr($bracketlink, 1));
427 // match the contents
428 preg_match("/([^|]+)(\|)?([^|]+)?/", $linkdata, $matches);
431 // if $matches[3] is set, this is a link in the form of:
432 // [some link name | http://blippy.com/]
434 if (isset($matches[3])) {
435 $URL = trim($matches[3]);
436 $linkname = htmlspecialchars(trim($matches[1]));
437 // assert proper URL's
438 if (preg_match("#^($AllowedProtocols):#", $URL)) {
439 $link['type'] = 'url-named';
440 $link['link'] = "<a href=\"$URL\">$linkname</a>";
442 $link['type'] = 'url-bad';
443 $link['link'] = "<b><u>BAD URL -- links have to start with one" .
444 "of $AllowedProtocols followed by ':'</u></b>";
450 // otherwise this is just a Wiki page like this: [page name]
451 // or a URL in brackets: [http://foo.com/]
453 if (isset($matches[1])) {
454 $linkname = trim($matches[1]);
455 if (IsWikiPage($dbi, $linkname)) {
456 $link['type'] = 'wiki';
457 $link['link'] = LinkExistingWikiWord($linkname);
458 } elseif (preg_match("#^($AllowedProtocols):#", $linkname)) {
459 // if it's an image, embed it; otherwise, it's a regular link
460 if (preg_match("/jpg$|png$|gif$/i", $linkname)) {
461 $link['type'] = 'url-image';
462 $link['link'] = LinkImage($linkname);
464 $link['type'] = 'url-simple';
465 $link['link'] = LinkURL($linkname);
468 $link['type'] = 'wiki-unknown';
469 $link['link'] = LinkUnknownWikiWord($linkname);
476 $link['type'] = 'unknown';
477 $link['link'] = $bracketlink;
482 function ExtractWikiPageLinks($content)
484 $wikilinks = array();
486 $numlines = count($content);
487 for($l = 0; $l < $numlines; $l++)
489 $line = $content[$l];
490 $numBracketLinks = preg_match_all("/\[\s*(.+?)\s*\]/", $line, $brktlinks);
491 for ($i = 0; $i < $numBracketLinks; $i++) {
492 $link = ParseAndLink($brktlinks[0][$i]);
493 if($link['type'] == 'wiki' || $link['type'] == 'wiki-unknown')
494 $wikilinks[$brktlinks[1][$i]]++;
496 $brktlink = preg_quote($brktlinks[0][$i]);
497 $line = preg_replace("|$brktlink|", '', $line);
500 if (preg_match_all("#!?\b(([A-Z][a-z]+){2,})\b#", $line, $link)) {
501 for ($i = 0; $link[0][$i]; $i++) {
502 if(!strstr($link[0][$i], '!'))
503 $wikilinks[$link[0][$i]]++;