1 <?php rcs_id('$Id: stdlib.php,v 1.21.2.1 2001-02-08 18:28:31 dairiki Exp $');
4 Standard functions for Wiki functionality
6 LinkExistingWikiWord($wikiword, $linktext)
7 LinkUnknownWikiWord($wikiword, $linktext)
8 LinkURL($url, $linktext)
10 RenderQuickSearch($value)
11 RenderFullSearch($value)
13 CookSpaces($pagearray)
14 class Stack (push(), pop(), cnt(), top())
15 SetHTMLOutputMode($newmode, $depth)
16 UpdateRecentChanges($dbi, $pagename, $isnewpage)
17 ParseAndLink($bracketlink)
18 ExtractWikiPageLinks($content)
19 LinkRelatedPages($dbi, $pagename)
20 GeneratePage($template, $content, $name, $hash)
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 LinkExistingWikiWord($wikiword, $linktext='') {
46 $enc_word = rawurlencode($wikiword);
48 $linktext = htmlspecialchars($wikiword);
49 return "<a href=\"$ScriptUrl?$enc_word\">$linktext</a>";
52 function LinkUnknownWikiWord($wikiword, $linktext='') {
54 $enc_word = rawurlencode($wikiword);
56 $linktext = htmlspecialchars($wikiword);
57 return "<u>$linktext</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
60 function LinkURL($url, $linktext='') {
62 if(ereg("[<>\"]", $url)) {
63 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
66 $linktext = htmlspecialchars($url);
67 return "<a href=\"$url\">$linktext</a>";
70 function LinkImage($url, $alt='[External Image]') {
72 if(ereg('[<>"]', $url)) {
73 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
75 return "<img src=\"$url\" ALT=\"$alt\">";
79 function RenderQuickSearch($value = '') {
81 return "<form action=\"$ScriptUrl\">\n" .
82 "<input type=text size=30 name=search value=\"$value\">\n" .
83 "<input type=submit value=\"". gettext("Search") .
87 function RenderFullSearch($value = '') {
89 return "<form action=\"$ScriptUrl\">\n" .
90 "<input type=text size=30 name=full value=\"$value\">\n" .
91 "<input type=submit value=\"". gettext("Search") .
95 function RenderMostPopular() {
96 global $ScriptUrl, $dbi;
98 $query = InitMostPopular($dbi, MOST_POPULAR_LIST_LENGTH);
100 while ($qhash = MostPopularNextMatch($dbi, $query)) {
101 $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
103 $result .= "</DL>\n";
109 function ParseAdminTokens($line) {
112 while (preg_match("/%%ADMIN-INPUT-(.*?)-(\w+)%%/", $line, $matches)) {
113 $head = str_replace('_', ' ', $matches[2]);
114 $form = "<FORM ACTION=\"$ScriptUrl\" METHOD=POST>"
115 ."$head: <INPUT NAME=$matches[1] SIZE=20> "
116 ."<INPUT TYPE=SUBMIT VALUE=\"" . gettext("Go") . "\">"
118 $line = str_replace($matches[0], $form, $line);
123 // converts spaces to tabs
124 function CookSpaces($pagearray) {
125 return preg_replace("/ {3,8}/", "\t", $pagearray);
130 var $items = array();
133 function push($item) {
134 $this->items[$this->size] = $item;
140 if ($this->size == 0) {
141 return false; // stack is empty
144 return $this->items[$this->size];
153 return $this->items[$this->size - 1];
159 // end class definition
162 // I couldn't move this to lib/config.php because it wasn't declared yet.
166 Wiki HTML output can, at any given time, be in only one mode.
167 It will be something like Unordered List, Preformatted Text,
168 plain text etc. When we change modes we have to issue close tags
169 for one mode and start tags for another.
171 $tag ... HTML tag to insert
172 $tagtype ... ZERO_LEVEL - close all open tags before inserting $tag
173 NESTED_LEVEL - close tags until depths match
174 $level ... nesting level (depth) of $tag
175 nesting is arbitrary limited to 10 levels
178 function SetHTMLOutputMode($tag, $tagtype, $level)
183 if ($tagtype == ZERO_LEVEL) {
184 // empty the stack until $level == 0;
185 if ($tag == $stack->top()) {
186 return; // same tag? -> nothing to do
188 while ($stack->cnt() > 0) {
189 $closetag = $stack->pop();
190 $retvar .= "</$closetag>\n";
194 $retvar .= "<$tag>\n";
199 } elseif ($tagtype == NESTED_LEVEL) {
200 if ($level < $stack->cnt()) {
201 // $tag has fewer nestings (old: tabs) than stack,
202 // reduce stack to that tab count
203 while ($stack->cnt() > $level) {
204 $closetag = $stack->pop();
205 if ($closetag == false) {
206 //echo "bounds error in tag stack";
209 $retvar .= "</$closetag>\n";
212 // if list type isn't the same,
213 // back up one more and push new tag
214 if ($tag != $stack->top()) {
215 $closetag = $stack->pop();
216 $retvar .= "</$closetag><$tag>\n";
220 } elseif ($level > $stack->cnt()) {
221 // we add the diff to the stack
222 // stack might be zero
223 while ($stack->cnt() < $level) {
224 $retvar .= "<$tag>\n";
226 if ($stack->cnt() > 10) {
227 // arbitrarily limit tag nesting
228 ExitWiki(gettext ("Stack bounds exceeded in SetHTMLOutputMode"));
232 } else { // $level == $stack->cnt()
233 if ($tag == $stack->top()) {
234 return; // same tag? -> nothing to do
236 // different tag - close old one, add new one
237 $closetag = $stack->pop();
238 $retvar .= "</$closetag>\n";
239 $retvar .= "<$tag>\n";
245 } else { // unknown $tagtype
246 ExitWiki ("Passed bad tag type value in SetHTMLOutputMode");
251 // end SetHTMLOutputMode
255 function ParseAndLink($bracketlink) {
256 global $dbi, $ScriptUrl, $AllowedProtocols, $InlineImages;
258 // $bracketlink will start and end with brackets; in between
259 // will be either a page name, a URL or both separated by a pipe.
261 // strip brackets and leading space
262 preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
263 // match the contents
264 preg_match("/([^|]+)(\|)?([^|]+)?/", $match[2], $matches);
266 if (isset($matches[3])) {
267 // named link of the form "[some link name | http://blippy.com/]"
268 $URL = trim($matches[3]);
269 $linkname = htmlspecialchars(trim($matches[1]));
272 // unnamed link of the form "[http://blippy.com/] or [wiki page]"
273 $URL = trim($matches[1]);
275 $linktype = 'simple';
278 if (IsWikiPage($dbi, $URL)) {
279 $link['type'] = "wiki-$linktype";
280 $link['link'] = LinkExistingWikiWord($URL, $linkname);
281 } elseif (preg_match("#^($AllowedProtocols):#", $URL)) {
282 // if it's an image, embed it; otherwise, it's a regular link
283 if (preg_match("/($InlineImages)$/i", $URL)) {
284 $link['type'] = "image-$linktype";
285 $link['link'] = LinkImage($URL, $linkname);
287 $link['type'] = "url-$linktype";
288 $link['link'] = LinkURL($URL, $linkname);
290 } elseif (preg_match("#^phpwiki:(.*)#", $URL, $match)) {
291 $link['type'] = "url-wiki-$linktype";
293 $linkname = htmlspecialchars($URL);
294 $link['link'] = "<a href=\"$ScriptUrl$match[1]\">$linkname</a>";
295 } elseif (preg_match("#^\d+$#", $URL)) {
296 $link['type'] = "reference-$linktype";
297 $link['link'] = $URL;
299 $link['type'] = "wiki-unknown-$linktype";
300 $link['link'] = LinkUnknownWikiWord($URL, $linkname);
307 function ExtractWikiPageLinks($content)
309 global $WikiNameRegexp;
311 $wikilinks = array();
312 $numlines = count($content);
313 for($l = 0; $l < $numlines; $l++)
315 // remove escaped '['
316 $line = str_replace('[[', ' ', $content[$l]);
318 // bracket links (only type wiki-* is of interest)
319 $numBracketLinks = preg_match_all("/\[\s*([^\]|]+\|)?\s*(.+?)\s*\]/", $line, $brktlinks);
320 for ($i = 0; $i < $numBracketLinks; $i++) {
321 $link = ParseAndLink($brktlinks[0][$i]);
322 if (preg_match("#^wiki#", $link['type']))
323 $wikilinks[$brktlinks[2][$i]] = 1;
325 $brktlink = preg_quote($brktlinks[0][$i]);
326 $line = preg_replace("|$brktlink|", '', $line);
329 // BumpyText old-style wiki links
330 if (preg_match_all("/!?$WikiNameRegexp/", $line, $link)) {
331 for ($i = 0; isset($link[0][$i]); $i++) {
332 if($link[0][$i][0] <> '!')
333 $wikilinks[$link[0][$i]] = 1;
341 function LinkRelatedPages($dbi, $pagename)
343 // currently not supported everywhere
344 if(!function_exists('GetWikiPageLinks'))
347 $links = GetWikiPageLinks($dbi, $pagename);
350 $txt .= sprintf (gettext ("%d best incoming links:"), NUM_RELATED_PAGES);
352 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
353 if(isset($links['in'][$i])) {
354 list($name, $score) = $links['in'][$i];
355 $txt .= LinkExistingWikiWord($name) . " ($score), ";
360 $txt .= sprintf (gettext ("%d best outgoing links:"), NUM_RELATED_PAGES);
362 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
363 if(isset($links['out'][$i])) {
364 list($name, $score) = $links['out'][$i];
365 if(IsWikiPage($dbi, $name))
366 $txt .= LinkExistingWikiWord($name) . " ($score), ";
371 $txt .= sprintf (gettext ("%d most popular nearby:"), NUM_RELATED_PAGES);
373 for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
374 if(isset($links['popular'][$i])) {
375 list($name, $score) = $links['popular'][$i];
376 $txt .= LinkExistingWikiWord($name) . " ($score), ";
384 # GeneratePage() -- takes $content and puts it in the template $template
385 # this function contains all the template logic
387 # $template ... name of the template (see config.php for list of names)
388 # $content ... html content to put into the page
389 # $name ... page title
390 # $hash ... if called while creating a wiki page, $hash points to
391 # the $pagehash array of that wiki page.
393 function GeneratePage($template, $content, $name, $hash)
395 global $ScriptUrl, $AllowedProtocols, $templates;
396 global $datetimeformat, $dbi, $logo, $FieldSeparator;
398 if (!is_array($hash))
401 function _dotoken ($id, $val, &$page) {
402 global $FieldSeparator;
403 $page = str_replace("$FieldSeparator#$id$FieldSeparator#",
407 function _iftoken ($id, $condition, &$page) {
408 global $FieldSeparator;
410 // line based IF directive
411 $lineyes = "$FieldSeparator#IF $id$FieldSeparator#";
412 $lineno = "$FieldSeparator#IF !$id$FieldSeparator#";
413 // block based IF directive
414 $blockyes = "$FieldSeparator#IF:$id$FieldSeparator#";
415 $blockyesend = "$FieldSeparator#ENDIF:$id$FieldSeparator#";
416 $blockno = "$FieldSeparator#IF:!$id$FieldSeparator#";
417 $blocknoend = "$FieldSeparator#ENDIF:!$id$FieldSeparator#";
420 $page = str_replace($lineyes, '', $page);
421 $page = str_replace($blockyes, '', $page);
422 $page = str_replace($blockyesend, '', $page);
423 $page = preg_replace("/$blockno(.*?)$blocknoend/s", '', $page);
424 $page = ereg_replace("${lineno}[^\n]*\n", '', $page);
426 $page = str_replace($lineno, '', $page);
427 $page = str_replace($blockno, '', $page);
428 $page = str_replace($blocknoend, '', $page);
429 $page = preg_replace("/$blockyes(.*?)$blockyesend/s", '', $page);
430 $page = ereg_replace("${lineyes}[^\n]*\n", '', $page);
434 $page = join('', file($templates[$template]));
435 $page = str_replace('###', "$FieldSeparator#", $page);
437 // valid for all pagetypes
438 _iftoken('COPY', isset($hash['copy']), $page);
439 _iftoken('LOCK', (isset($hash['flags']) &&
440 ($hash['flags'] & FLAG_PAGE_LOCKED)), $page);
441 _iftoken('ADMIN', defined('WIKI_ADMIN'), $page);
443 _dotoken('SCRIPTURL', $ScriptUrl, $page);
444 _dotoken('PAGE', htmlspecialchars($name), $page);
445 _dotoken('ALLOWEDPROTOCOLS', $AllowedProtocols, $page);
446 _dotoken('LOGO', $logo, $page);
448 // invalid for messages (search results, error messages)
449 if ($template != 'MESSAGE') {
450 _dotoken('PAGEURL', rawurlencode($name), $page);
451 _dotoken('LASTMODIFIED',
452 date($datetimeformat, $hash['lastmodified']), $page);
453 _dotoken('LASTAUTHOR', $hash['author'], $page);
454 _dotoken('VERSION', $hash['version'], $page);
455 if (strstr($page, "$FieldSeparator#HITS$FieldSeparator#")) {
456 _dotoken('HITS', GetHitCount($dbi, $name), $page);
458 if (strstr($page, "$FieldSeparator#RELATEDPAGES$FieldSeparator#")) {
459 _dotoken('RELATEDPAGES', LinkRelatedPages($dbi, $name), $page);
463 // valid only for EditLinks
464 if ($template == 'EDITLINKS') {
465 for ($i = 1; $i <= NUM_LINKS; $i++) {
466 $ref = isset($hash['refs'][$i]) ? $hash['refs'][$i] : '';
467 _dotoken("R$i", $ref, $page);
471 _dotoken('CONTENT', $content, $page);