2 rcs_id('$Id: stdlib.php,v 1.14 2000-12-06 10:59:27 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, $linktext='') {
170 $enc_word = rawurlencode($wikiword);
172 $linktext = htmlspecialchars($wikiword);
173 return "<a href=\"$ScriptUrl?$enc_word\">$linktext</a>";
176 function LinkUnknownWikiWord($wikiword, $linktext='') {
178 $enc_word = rawurlencode($wikiword);
180 $linktext = htmlspecialchars($wikiword);
181 return "<u>$linktext</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
184 function LinkURL($url) {
186 if(ereg("[<>\"]", $url)) {
187 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
189 $enc_url = htmlspecialchars($url);
190 return "<a href=\"$url\">$enc_url</a>";
194 function LinkImage($url, $alt="[External Image]") {
196 if(ereg("[<>\"]", $url)) {
197 return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
199 return "<img src=\"$url\" ALT=\"$alt\">";
203 function RenderQuickSearch($value = "") {
205 return "<form action=\"$ScriptUrl\">\n" .
206 "<input type=text size=30 name=search value=\"$value\">\n" .
207 "<input type=submit value=\"". gettext("Search") .
211 function RenderFullSearch($value = "") {
213 return "<form action=\"$ScriptUrl\">\n" .
214 "<input type=text size=30 name=full value=\"$value\">\n" .
215 "<input type=submit value=\"". gettext("Search") .
219 function RenderMostPopular() {
220 global $ScriptUrl, $dbi;
222 $query = InitMostPopular($dbi, MOST_POPULAR_LIST_LENGTH);
224 while ($qhash = MostPopularNextMatch($dbi, $query)) {
225 $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
227 $result .= "</DL>\n";
232 function ParseAdminTokens($line) {
235 while (preg_match("/%%ADMIN-INPUT-(.*?)-(\w+)%%/", $line, $matches)) {
236 $head = str_replace("_", " ", $matches[2]);
237 $form = "<FORM ACTION=\"$ScriptUrl\" METHOD=POST>"
238 ."$head: <INPUT NAME=$matches[1] SIZE=20> "
239 ."<INPUT TYPE=SUBMIT VALUE=\"" . gettext("Go") . "\">"
241 $line = str_replace($matches[0], $form, $line);
246 // converts spaces to tabs
247 function CookSpaces($pagearray) {
248 return preg_replace("/ {3,8}/", "\t", $pagearray);
253 var $items = array();
256 function push($item) {
257 $this->items[$this->size] = $item;
263 if ($this->size == 0) {
264 return false; // stack is empty
267 return $this->items[$this->size];
276 return $this->items[$this->size - 1];
282 // end class definition
285 // I couldn't move this to lib/config.php because it
286 // wasn't declared yet.
290 Wiki HTML output can, at any given time, be in only one mode.
291 It will be something like Unordered List, Preformatted Text,
292 plain text etc. When we change modes we have to issue close tags
293 for one mode and start tags for another.
296 function SetHTMLOutputMode($tag, $tagdepth, $tabcount) {
300 if ($tagdepth == SINGLE_DEPTH) {
301 if ($tabcount < $stack->cnt()) {
302 // there are fewer tabs than stack,
303 // reduce stack to that tab count
304 while ($stack->cnt() > $tabcount) {
305 $closetag = $stack->pop();
306 if ($closetag == false) {
307 //echo "bounds error in tag stack";
310 $retvar .= "</$closetag>\n";
313 // if list type isn't the same,
314 // back up one more and push new tag
315 if ($tag != $stack->top()) {
316 $closetag = $stack->pop();
317 $retvar .= "</$closetag><$tag>\n";
321 } elseif ($tabcount > $stack->cnt()) {
322 // we add the diff to the stack
323 // stack might be zero
324 while ($stack->cnt() < $tabcount) {
326 $retvar .= "<$tag>\n";
328 if ($stack->cnt() > 10) {
329 // arbitrarily limit tag nesting
330 ExitWiki(gettext ("Stack bounds exceeded in SetHTMLOutputMode"));
335 if ($tag == $stack->top()) {
338 $closetag = $stack->pop();
339 #echo "</$closetag>\n";
341 $retvar .= "</$closetag>\n";
342 $retvar .= "<$tag>\n";
347 } elseif ($tagdepth == ZERO_DEPTH) {
348 // empty the stack for $depth == 0;
349 // what if the stack is empty?
350 if ($tag == $stack->top()) {
353 while ($stack->cnt() > 0) {
354 $closetag = $stack->pop();
355 #echo "</$closetag>\n";
356 $retvar .= "</$closetag>\n";
361 $retvar .= "<$tag>\n";
367 ExitWiki ("Passed bad tag depth value in SetHTMLOutputMode");
373 // end SetHTMLOutputMode
377 // The Recent Changes file is solely handled here
378 function UpdateRecentChanges($dbi, $pagename, $isnewpage) {
380 global $remoteuser; // this is set in the config
382 global $WikiPageStore;
384 $recentchanges = RetrievePage($dbi, gettext ("RecentChanges"),
387 // this shouldn't be necessary, since PhpWiki loads
388 // default pages if this is a new baby Wiki
389 if ($recentchanges == -1) {
390 $recentchanges = array();
394 $today = date($dateformat, $now);
396 if (date($dateformat, $recentchanges["lastmodified"]) != $today) {
398 $recentchanges["lastmodified"] = $now;
403 $numlines = sizeof($recentchanges["content"]);
407 // scroll through the page to the first date and break
408 // dates are marked with "____" at the beginning of the line
409 for ($i = 0; $i < $numlines; $i++) {
410 if (preg_match("/^____/",
411 $recentchanges["content"][$i])) {
414 $newpage[$k++] = $recentchanges["content"][$i];
418 // if it's a new date, insert it, else add the updated page's
421 $newpage[$k++] = $isNewDay ? "____$today\r"
422 : $recentchanges["content"][$i++];
424 $newpage[$k++] = "* [$pagename] (new) ..... $remoteuser\r";
426 $diffurl = "phpwiki:?diff=" . rawurlencode($pagename);
427 $newpage[$k++] = "* [$pagename] ([diff|$diffurl]) ..... $remoteuser\r";
430 $newpage[$k++] = "\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 (IsWikiPage($dbi, $URL)) {
469 $link['type'] = 'wiki-named';
470 $link['link'] = LinkExistingWikiWord($URL, $linkname);
471 } elseif (preg_match("#^($AllowedProtocols):#", $URL)) {
472 if (preg_match("/($InlineImages)$/i", $URL)) {
473 $link['type'] = 'image-named';
474 $link['link'] = LinkImage($URL, $linkname);
476 $link['type'] = 'url-named';
477 $link['link'] = "<a href=\"$URL\">$linkname</a>";
479 } elseif (preg_match("#^phpwiki:(.*)#", $URL, $match)) {
480 $link['type'] = 'url-wiki-named';
481 $link['link'] = "<a href=\"$ScriptUrl$match[1]\">$linkname</a>";
483 $link['type'] = 'wiki-unknown-named';
484 $link['link'] = LinkUnknownWikiWord($URL, $linkname);
490 // otherwise this is just a Wiki page like this: [page name]
491 // or a URL in brackets: [http://foo.com/]
493 if (isset($matches[1])) {
494 $linkname = trim($matches[1]);
495 if (IsWikiPage($dbi, $linkname)) {
496 $link['type'] = 'wiki';
497 $link['link'] = LinkExistingWikiWord($linkname);
498 } elseif (preg_match("#^($AllowedProtocols):#", $linkname)) {
499 // if it's an image, embed it; otherwise, it's a regular link
500 if (preg_match("/($InlineImages)$/i", $linkname)) {
501 $link['type'] = 'image-simple';
502 $link['link'] = LinkImage($linkname);
504 $link['type'] = 'url-simple';
505 $link['link'] = LinkURL($linkname);
508 $link['type'] = 'wiki-unknown';
509 $link['link'] = LinkUnknownWikiWord($linkname);
514 $link['type'] = 'unknown';
515 $link['link'] = $bracketlink;
520 function ExtractWikiPageLinks($content)
522 global $WikiNameRegexp;
524 $wikilinks = array();
525 $numlines = count($content);
526 for($l = 0; $l < $numlines; $l++)
528 $line = str_replace('[[', ' ', $content[$l]); // remove escaped '['
529 $numBracketLinks = preg_match_all("/\[\s*([^\]|]+\|)?\s*(.+?)\s*\]/", $line, $brktlinks);
530 for ($i = 0; $i < $numBracketLinks; $i++) {
531 $link = ParseAndLink($brktlinks[0][$i]);
532 if (preg_match("#^wiki#", $link['type']))
533 $wikilinks[$brktlinks[2][$i]] = 1;
535 $brktlink = preg_quote($brktlinks[0][$i]);
536 $line = preg_replace("|$brktlink|", '', $line);
539 if (preg_match_all("/!?$WikiNameRegexp/", $line, $link)) {
540 for ($i = 0; isset($link[0][$i]); $i++) {
541 if($link[0][$i][0] <> '!')
542 $wikilinks[$link[0][$i]] = 1;