]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/stdlib.php
moved UpdateRecentChanges() to savepage.php
[SourceForge/phpwiki.git] / lib / stdlib.php
1 <?php rcs_id('$Id: stdlib.php,v 1.19 2001-01-04 18:32:25 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    function GeneratePage($template, $content, $name, $hash)
382    {
383       global $ScriptUrl, $AllowedProtocols, $templates;
384       global $datetimeformat, $dbi, $logo, $FieldSeparator;
385
386       if (!is_array($hash))
387          unset($hash);
388
389       function _dotoken ($id, $val, &$page) {
390          global $FieldSeparator;
391          $page = str_replace("$FieldSeparator#$id$FieldSeparator#",
392                                 $val, $page);
393       }
394
395       function _iftoken ($id, $condition, &$page) {
396          global $FieldSeparator;
397
398          // line based IF directive
399          $lineyes = "$FieldSeparator#IF $id$FieldSeparator#";
400          $lineno = "$FieldSeparator#IF !$id$FieldSeparator#";
401          // block based IF directive
402          $blockyes = "$FieldSeparator#IF:$id$FieldSeparator#";
403          $blockyesend = "$FieldSeparator#ENDIF:$id$FieldSeparator#";
404          $blockno = "$FieldSeparator#IF:!$id$FieldSeparator#";
405          $blocknoend = "$FieldSeparator#ENDIF:!$id$FieldSeparator#";
406
407          if ($condition) {
408             $page = str_replace($lineyes, '', $page);
409             $page = str_replace($blockyes, '', $page);
410             $page = str_replace($blockyesend, '', $page);
411             $page = preg_replace("/$blockno(.*?)$blocknoend/s", '', $page);
412             $page = ereg_replace("${lineno}[^\n]*\n", '', $page);
413          } else {
414             $page = str_replace($lineno, '', $page);
415             $page = str_replace($blockno, '', $page);
416             $page = str_replace($blocknoend, '', $page);
417             $page = preg_replace("/$blockyes(.*?)$blockyesend/s", '', $page);
418             $page = ereg_replace("${lineyes}[^\n]*\n", '', $page);
419          }
420       }
421
422       $page = join('', file($templates[$template]));
423       $page = str_replace('###', "$FieldSeparator#", $page);
424
425       // valid for all pagetypes
426       _iftoken('COPY', isset($hash['copy']), $page);
427       _iftoken('LOCK',  (isset($hash['flags']) &&
428                         ($hash['flags'] & FLAG_PAGE_LOCKED)), $page);
429       _iftoken('ADMIN', defined('WIKI_ADMIN'), $page);
430
431       _dotoken('SCRIPTURL', $ScriptUrl, $page);
432       _dotoken('PAGE', htmlspecialchars($name), $page);
433       _dotoken('ALLOWEDPROTOCOLS', $AllowedProtocols, $page);
434       _dotoken('LOGO', $logo, $page);
435       
436       // invalid for messages (search results, error messages)
437       if ($template != 'MESSAGE') {
438          _dotoken('PAGEURL', rawurlencode($name), $page);
439          _dotoken('LASTMODIFIED',
440                         date($datetimeformat, $hash['lastmodified']), $page);
441          _dotoken('LASTAUTHOR', $hash['author'], $page);
442          _dotoken('VERSION', $hash['version'], $page);
443          if (strstr($page, "$FieldSeparator#HITS$FieldSeparator#")) {
444             _dotoken('HITS', GetHitCount($dbi, $name), $page);
445          }
446          if (strstr($page, "$FieldSeparator#RELATEDPAGES$FieldSeparator#")) {
447             _dotoken('RELATEDPAGES', LinkRelatedPages($dbi, $name), $page);
448          }
449       }
450
451       // valid only for EditLinks
452       if ($template == 'EDITLINKS') {
453          for ($i = 1; $i <= NUM_LINKS; $i++) {
454             $ref = isset($hash['refs'][$i]) ? $hash['refs'][$i] : '';
455             _dotoken("R$i", $ref, $page);
456          }
457       }
458
459       _dotoken('CONTENT', $content, $page);
460       print $page;
461    }
462 ?>