]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/stdlib.php
added description to GeneratePage()
[SourceForge/phpwiki.git] / lib / stdlib.php
1 <?php rcs_id('$Id: stdlib.php,v 1.20 2001-01-09 18:22:49 ahollosi Exp $');
2
3    /*
4       Standard functions for Wiki functionality
5          ExitWiki($errormsg)
6          LinkExistingWikiWord($wikiword) 
7          LinkUnknownWikiWord($wikiword) 
8          LinkURL($url, $linktext)
9          LinkImage($url, $alt)
10          RenderQuickSearch($value)
11          RenderFullSearch($value)
12          RenderMostPopular()
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)
21    */
22
23
24    function ExitWiki($errormsg)
25    {
26       static $exitwiki = 0;
27       global $dbi;
28
29       if($exitwiki)             // just in case CloseDataBase calls us
30          exit();
31       $exitwiki = 1;
32
33       CloseDataBase($dbi);
34
35       if($errormsg <> '') {
36          print "<P><hr noshade><h2>" . gettext("WikiFatalError") . "</h2>\n";
37          print $errormsg;
38          print "\n</BODY></HTML>";
39       }
40       exit;
41    }
42
43
44    function LinkExistingWikiWord($wikiword, $linktext='') {
45       global $ScriptUrl;
46       $enc_word = rawurlencode($wikiword);
47       if(empty($linktext))
48          $linktext = htmlspecialchars($wikiword);
49       return "<a href=\"$ScriptUrl?$enc_word\">$linktext</a>";
50    }
51
52    function LinkUnknownWikiWord($wikiword, $linktext='') {
53       global $ScriptUrl;
54       $enc_word = rawurlencode($wikiword);
55       if(empty($linktext))
56          $linktext = htmlspecialchars($wikiword);
57       return "<u>$linktext</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
58    }
59
60    function LinkURL($url, $linktext='') {
61       global $ScriptUrl;
62       if(ereg("[<>\"]", $url)) {
63          return "<b><u>BAD URL -- remove all of &lt;, &gt;, &quot;</u></b>";
64       }
65       if(empty($linktext))
66          $linktext = htmlspecialchars($url);
67       return "<a href=\"$url\">$linktext</a>";
68    }
69
70    function LinkImage($url, $alt='[External Image]') {
71       global $ScriptUrl;
72       if(ereg('[<>"]', $url)) {
73          return "<b><u>BAD URL -- remove all of &lt;, &gt;, &quot;</u></b>";
74       }
75       return "<img src=\"$url\" ALT=\"$alt\">";
76    }
77
78    
79    function RenderQuickSearch($value = '') {
80       global $ScriptUrl;
81       return "<form action=\"$ScriptUrl\">\n" .
82              "<input type=text size=30 name=search value=\"$value\">\n" .
83              "<input type=submit value=\"". gettext("Search") .
84              "\"></form>\n";
85    }
86
87    function RenderFullSearch($value = '') {
88       global $ScriptUrl;
89       return "<form action=\"$ScriptUrl\">\n" .
90              "<input type=text size=30 name=full value=\"$value\">\n" .
91              "<input type=submit value=\"". gettext("Search") .
92              "\"></form>\n";
93    }
94
95    function RenderMostPopular() {
96       global $ScriptUrl, $dbi;
97       
98       $query = InitMostPopular($dbi, MOST_POPULAR_LIST_LENGTH);
99       $result = "<DL>\n";
100       while ($qhash = MostPopularNextMatch($dbi, $query)) {
101          $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
102       }
103       $result .= "</DL>\n";
104       
105       return $result;
106    }
107
108
109    function ParseAdminTokens($line) {
110       global $ScriptUrl;
111       
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") . "\">"
117                 ."</FORM>";
118          $line = str_replace($matches[0], $form, $line);
119       }
120       return $line;
121    }
122
123    // converts spaces to tabs
124    function CookSpaces($pagearray) {
125       return preg_replace("/ {3,8}/", "\t", $pagearray);
126    }
127
128
129    class Stack {
130       var $items = array();
131       var $size = 0;
132
133       function push($item) {
134          $this->items[$this->size] = $item;
135          $this->size++;
136          return true;
137       }  
138    
139       function pop() {
140          if ($this->size == 0) {
141             return false; // stack is empty
142          }  
143          $this->size--;
144          return $this->items[$this->size];
145       }  
146    
147       function cnt() {
148          return $this->size;
149       }  
150
151       function top() {
152          if($this->size)
153             return $this->items[$this->size - 1];
154          else
155             return '';
156       }  
157
158    }  
159    // end class definition
160
161
162    // I couldn't move this to lib/config.php because it wasn't declared yet.
163    $stack = new Stack;
164
165    /* 
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.
170
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
176    */
177
178    function SetHTMLOutputMode($tag, $tagtype, $level)
179    {
180       global $stack;
181       $retvar = '';
182
183       if ($tagtype == ZERO_LEVEL) {
184          // empty the stack until $level == 0;
185          if ($tag == $stack->top()) {
186             return; // same tag? -> nothing to do
187          }
188          while ($stack->cnt() > 0) {
189             $closetag = $stack->pop();
190             $retvar .= "</$closetag>\n";
191          }
192    
193          if ($tag) {
194             $retvar .= "<$tag>\n";
195             $stack->push($tag);
196          }
197
198
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";
207                   break;
208                }
209                $retvar .= "</$closetag>\n";
210             }
211
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";
217                $stack->push($tag);
218             }
219    
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";
225                $stack->push($tag);
226                if ($stack->cnt() > 10) {
227                   // arbitrarily limit tag nesting
228                   ExitWiki(gettext ("Stack bounds exceeded in SetHTMLOutputMode"));
229                }
230             }
231    
232          } else { // $level == $stack->cnt()
233             if ($tag == $stack->top()) {
234                return; // same tag? -> nothing to do
235             } else {
236                // different tag - close old one, add new one
237                $closetag = $stack->pop();
238                $retvar .= "</$closetag>\n";
239                $retvar .= "<$tag>\n";
240                $stack->push($tag);
241             }
242          }
243
244    
245       } else { // unknown $tagtype
246          ExitWiki ("Passed bad tag type value in SetHTMLOutputMode");
247       }
248
249       return $retvar;
250    }
251    // end SetHTMLOutputMode
252
253
254
255    function ParseAndLink($bracketlink) {
256       global $dbi, $ScriptUrl, $AllowedProtocols, $InlineImages;
257
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.
260
261       // strip brackets and leading space
262       preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
263       // match the contents 
264       preg_match("/([^|]+)(\|)?([^|]+)?/", $match[2], $matches);
265
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]));
270          $linktype = 'named';
271       } else {
272          // unnamed link of the form "[http://blippy.com/] or [wiki page]"
273          $URL = trim($matches[1]);
274          $linkname = '';
275          $linktype = 'simple';
276       }
277
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);
286          } else {
287             $link['type'] = "url-$linktype";
288             $link['link'] = LinkURL($URL, $linkname);
289          }
290       } elseif (preg_match("#^phpwiki:(.*)#", $URL, $match)) {
291          $link['type'] = "url-wiki-$linktype";
292          if(empty($linkname))
293             $linkname = htmlspecialchars($URL);
294          $link['link'] = "<a href=\"$ScriptUrl$match[1]\">$linkname</a>";
295       } else {
296          $link['type'] = "wiki-unknown-$linktype";
297          $link['link'] = LinkUnknownWikiWord($URL, $linkname);
298       }
299
300       return $link;
301    }
302
303
304    function ExtractWikiPageLinks($content)
305    {
306       global $WikiNameRegexp;
307
308       $wikilinks = array();
309       $numlines = count($content);
310       for($l = 0; $l < $numlines; $l++)
311       {
312          // remove escaped '['
313          $line = str_replace('[[', ' ', $content[$l]);
314
315          // bracket links (only type wiki-* is of interest)
316          $numBracketLinks = preg_match_all("/\[\s*([^\]|]+\|)?\s*(.+?)\s*\]/", $line, $brktlinks);
317          for ($i = 0; $i < $numBracketLinks; $i++) {
318             $link = ParseAndLink($brktlinks[0][$i]);
319             if (preg_match("#^wiki#", $link['type']))
320                $wikilinks[$brktlinks[2][$i]] = 1;
321
322             $brktlink = preg_quote($brktlinks[0][$i]);
323             $line = preg_replace("|$brktlink|", '', $line);
324          }
325
326          // BumpyText old-style wiki links
327          if (preg_match_all("/!?$WikiNameRegexp/", $line, $link)) {
328             for ($i = 0; isset($link[0][$i]); $i++) {
329                if($link[0][$i][0] <> '!')
330                   $wikilinks[$link[0][$i]] = 1;
331             }
332          }
333       }
334       return $wikilinks;
335    }      
336
337
338    function LinkRelatedPages($dbi, $pagename)
339    {
340       // currently not supported everywhere
341       if(!function_exists('GetWikiPageLinks'))
342          return '';
343
344       $links = GetWikiPageLinks($dbi, $pagename);
345
346       $txt = "<b>";
347       $txt .= sprintf (gettext ("%d best incoming links:"), NUM_RELATED_PAGES);
348       $txt .= "</b>\n";
349       for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
350          if(isset($links['in'][$i])) {
351             list($name, $score) = $links['in'][$i];
352             $txt .= LinkExistingWikiWord($name) . " ($score), ";
353          }
354       }
355
356       $txt .= "\n<br><b>";
357       $txt .= sprintf (gettext ("%d best outgoing links:"), NUM_RELATED_PAGES);
358       $txt .= "</b>\n";
359       for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
360          if(isset($links['out'][$i])) {
361             list($name, $score) = $links['out'][$i];
362             if(IsWikiPage($dbi, $name))
363                $txt .= LinkExistingWikiWord($name) . " ($score), ";
364          }
365       }
366
367       $txt .= "\n<br><b>";
368       $txt .= sprintf (gettext ("%d most popular nearby:"), NUM_RELATED_PAGES);
369       $txt .= "</b>\n";
370       for($i = 0; $i < NUM_RELATED_PAGES; $i++) {
371          if(isset($links['popular'][$i])) {
372             list($name, $score) = $links['popular'][$i];
373             $txt .= LinkExistingWikiWord($name) . " ($score), ";
374          }
375       }
376       
377       return $txt;
378    }
379
380    
381    # GeneratePage() -- takes $content and puts it in the template $template
382    # this function contains all the template logic
383    #
384    # $template ... name of the template (see config.php for list of names)
385    # $content ... html content to put into the page
386    # $name ... page title
387    # $hash ... if called while creating a wiki page, $hash points to
388    #           the $pagehash array of that wiki page.
389
390    function GeneratePage($template, $content, $name, $hash)
391    {
392       global $ScriptUrl, $AllowedProtocols, $templates;
393       global $datetimeformat, $dbi, $logo, $FieldSeparator;
394
395       if (!is_array($hash))
396          unset($hash);
397
398       function _dotoken ($id, $val, &$page) {
399          global $FieldSeparator;
400          $page = str_replace("$FieldSeparator#$id$FieldSeparator#",
401                                 $val, $page);
402       }
403
404       function _iftoken ($id, $condition, &$page) {
405          global $FieldSeparator;
406
407          // line based IF directive
408          $lineyes = "$FieldSeparator#IF $id$FieldSeparator#";
409          $lineno = "$FieldSeparator#IF !$id$FieldSeparator#";
410          // block based IF directive
411          $blockyes = "$FieldSeparator#IF:$id$FieldSeparator#";
412          $blockyesend = "$FieldSeparator#ENDIF:$id$FieldSeparator#";
413          $blockno = "$FieldSeparator#IF:!$id$FieldSeparator#";
414          $blocknoend = "$FieldSeparator#ENDIF:!$id$FieldSeparator#";
415
416          if ($condition) {
417             $page = str_replace($lineyes, '', $page);
418             $page = str_replace($blockyes, '', $page);
419             $page = str_replace($blockyesend, '', $page);
420             $page = preg_replace("/$blockno(.*?)$blocknoend/s", '', $page);
421             $page = ereg_replace("${lineno}[^\n]*\n", '', $page);
422          } else {
423             $page = str_replace($lineno, '', $page);
424             $page = str_replace($blockno, '', $page);
425             $page = str_replace($blocknoend, '', $page);
426             $page = preg_replace("/$blockyes(.*?)$blockyesend/s", '', $page);
427             $page = ereg_replace("${lineyes}[^\n]*\n", '', $page);
428          }
429       }
430
431       $page = join('', file($templates[$template]));
432       $page = str_replace('###', "$FieldSeparator#", $page);
433
434       // valid for all pagetypes
435       _iftoken('COPY', isset($hash['copy']), $page);
436       _iftoken('LOCK',  (isset($hash['flags']) &&
437                         ($hash['flags'] & FLAG_PAGE_LOCKED)), $page);
438       _iftoken('ADMIN', defined('WIKI_ADMIN'), $page);
439
440       _dotoken('SCRIPTURL', $ScriptUrl, $page);
441       _dotoken('PAGE', htmlspecialchars($name), $page);
442       _dotoken('ALLOWEDPROTOCOLS', $AllowedProtocols, $page);
443       _dotoken('LOGO', $logo, $page);
444       
445       // invalid for messages (search results, error messages)
446       if ($template != 'MESSAGE') {
447          _dotoken('PAGEURL', rawurlencode($name), $page);
448          _dotoken('LASTMODIFIED',
449                         date($datetimeformat, $hash['lastmodified']), $page);
450          _dotoken('LASTAUTHOR', $hash['author'], $page);
451          _dotoken('VERSION', $hash['version'], $page);
452          if (strstr($page, "$FieldSeparator#HITS$FieldSeparator#")) {
453             _dotoken('HITS', GetHitCount($dbi, $name), $page);
454          }
455          if (strstr($page, "$FieldSeparator#RELATEDPAGES$FieldSeparator#")) {
456             _dotoken('RELATEDPAGES', LinkRelatedPages($dbi, $name), $page);
457          }
458       }
459
460       // valid only for EditLinks
461       if ($template == 'EDITLINKS') {
462          for ($i = 1; $i <= NUM_LINKS; $i++) {
463             $ref = isset($hash['refs'][$i]) ? $hash['refs'][$i] : '';
464             _dotoken("R$i", $ref, $page);
465          }
466       }
467
468       _dotoken('CONTENT', $content, $page);
469       print $page;
470    }
471 ?>