]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/stdlib.php
ExitWiki() function replaces simple calls to exit()
[SourceForge/phpwiki.git] / lib / stdlib.php
1 <!-- $Id: stdlib.php,v 1.3 2000-10-19 22:25:45 ahollosi Exp $ -->
2 <?php
3    /*
4       Standard functions for Wiki functionality
5          LinkRelatedPages($dbi, $pagename)
6          GeneratePage($template, $content, $name, $hash)
7          LinkExistingWikiWord($wikiword) 
8          LinkUnknownWikiWord($wikiword) 
9          LinkURL($url)
10          LinkImage($url)
11          RenderQuickSearch() 
12          RenderFullSearch() 
13          RenderMostPopular()
14          CookSpaces($pagearray) 
15          class Stack
16          SetHTMLOutputMode($newmode, $depth)
17          UpdateRecentChanges($dbi, $pagename, $isnewpage) 
18          ParseAndLink($bracketlink)
19          ExtractWikiPageLinks($content)
20          ExitWiki($errormsg)
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>WikiFatalError</h2>\n";
37          print $errormsg;
38          print "\n</BODY></HTML>";
39       }
40       exit();
41    }
42
43
44    function LinkRelatedPages($dbi, $pagename)
45    {
46       // currently not supported everywhere
47       if(!function_exists('GetWikiPageLinks'))
48          return '';
49
50       $links = GetWikiPageLinks($dbi, $pagename);
51
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), ";
57          }
58       }
59
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), ";
66          }
67       }
68
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), ";
74          }
75       }
76       
77       return $txt;
78    }
79
80    
81    function GeneratePage($template, $content, $name, $hash)
82    {
83       global $ScriptUrl, $AllowedProtocols, $templates;
84       global $datetimeformat, $dbi, $logo;
85
86       if (!is_array($hash))
87          unset($hash);
88
89       $page = join('', file($templates[$template]));
90       $page = str_replace('###', "#$FieldSeparator#", $page);
91
92       // valid for all pagetypes
93       $page = str_replace("#$FieldSeparator#SCRIPTURL#$FieldSeparator#",
94                         $ScriptUrl, $page);
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#",
100                         $logo, $page);
101
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);
115          }
116          if (strstr($page, "#$FieldSeparator#RELATEDPAGES#$FieldSeparator#")) {
117             $page = str_replace("#$FieldSeparator#RELATEDPAGES#$FieldSeparator#",
118                         LinkRelatedPages($dbi, $name), $page);
119          }
120       }
121
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);
127       }
128
129       if ($hash['copy']) {
130          $page = str_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#",
131                         '', $page);
132       } else {
133          $page = ereg_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#[^\n]*",
134                         '', $page);
135       }
136
137       $page = str_replace("#$FieldSeparator#CONTENT#$FieldSeparator#",
138                         $content, $page);
139       print $page;
140    }
141
142
143    function LinkExistingWikiWord($wikiword) {
144       global $ScriptUrl;
145       $enc_word = rawurlencode($wikiword);
146       $wikiword = htmlspecialchars($wikiword);
147       return "<a href=\"$ScriptUrl?$enc_word\">$wikiword</a>";
148    }
149
150    function LinkUnknownWikiWord($wikiword) {
151       global $ScriptUrl;
152       $enc_word = rawurlencode($wikiword);
153       $wikiword = htmlspecialchars($wikiword);
154       return "<u>$wikiword</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
155    }
156
157    function LinkURL($url) {
158       global $ScriptUrl;
159       if(ereg("[<>\"]", $url)) {
160          return "<b><u>BAD URL -- remove all of &lt;, &gt;, &quot;</u></b>";
161       }
162       $enc_url = htmlspecialchars($url);
163       return "<a href=\"$url\">$enc_url</a>";
164    }
165
166
167    function LinkImage($url) {
168       global $ScriptUrl;
169       if(ereg("[<>\"]", $url)) {
170          return "<b><u>BAD URL -- remove all of &lt;, &gt;, &quot;</u></b>";
171       }
172       return "<img src=\"$url\">";
173    }
174
175    
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";
179       return $formtext;
180    }
181
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";
185       return $formtext;
186    }
187
188    function RenderMostPopular() {
189       global $ScriptUrl, $dbi;
190       
191       $query = InitMostPopular($dbi, MOST_POPULAR_LIST_LENGTH);
192       $result = "<DL>\n";
193       while ($qhash = MostPopularNextMatch($dbi, $query)) {
194          $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
195       }
196       $result .= "</DL>\n";
197       
198       return $result;
199    }
200
201    // converts spaces to tabs
202    function CookSpaces($pagearray) {
203       return preg_replace("/ {3,8}/", "\t", $pagearray);
204    }
205
206
207    class Stack {
208       var $items;
209       var $size = 0;
210
211       function push($item) {
212          $this->items[$this->size] = $item;
213          $this->size++;
214          return true;
215       }  
216    
217       function pop() {
218          if ($this->size == 0) {
219             return false; // stack is empty
220          }  
221          $this->size--;
222          return $this->items[$this->size];
223       }  
224    
225       function cnt() {
226          return $this->size;
227       }  
228
229       function top() {
230          return $this->items[$this->size - 1];
231       }  
232
233    }  
234    // end class definition
235
236
237    // I couldn't move this to lib/config.php because it 
238    // wasn't declared yet.
239    $stack = new Stack;
240
241    /* 
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.
246    */
247
248    function SetHTMLOutputMode($tag, $tagdepth, $tabcount) {
249       global $stack;
250       $retvar = "";
251    
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";
260                   break;
261                }
262                $retvar .= "</$closetag>\n";
263             }
264
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";
270                $stack->push($tag);
271             }
272    
273          } elseif ($tabcount > $stack->cnt()) {
274             // we add the diff to the stack
275             // stack might be zero
276             while ($stack->cnt() < $tabcount) {
277                #echo "<$tag>\n";
278                $retvar .= "<$tag>\n";
279                $stack->push($tag);
280                if ($stack->cnt() > 10) {
281                   // arbitrarily limit tag nesting
282                   ExitWiki("Stack bounds exceeded in SetHTMLOutputMode");
283                }
284             }
285    
286          } else {
287             if ($tag == $stack->top()) {
288                return;
289             } else {
290                $closetag = $stack->pop();
291                #echo "</$closetag>\n";
292                #echo "<$tag>\n";
293                $retvar .= "</$closetag>\n";
294                $retvar .= "<$tag>\n";
295                $stack->push($tag);
296             }
297          }
298    
299       } elseif ($tagdepth == ZERO_DEPTH) {
300          // empty the stack for $depth == 0;
301          // what if the stack is empty?
302          if ($tag == $stack->top()) {
303             return;
304          }
305          while ($stack->cnt() > 0) {
306             $closetag = $stack->pop();
307             #echo "</$closetag>\n";
308             $retvar .= "</$closetag>\n";
309          }
310    
311          if ($tag) {
312             #echo "<$tag>\n";
313             $retvar .= "<$tag>\n";
314             $stack->push($tag);
315          }
316    
317       } else {    // error
318          ExitWiki("Passed bad tag depth value in SetHTMLOutputMode");
319       }
320
321       return $retvar;
322
323    }
324    // end SetHTMLOutputMode
325
326
327
328    // The Recent Changes file is solely handled here
329    function UpdateRecentChanges($dbi, $pagename, $isnewpage) {
330
331       global $remoteuser; // this is set in the config
332       global $dateformat;
333       global $ScriptUrl;
334       global $WikiPageStore;
335
336       $recentchanges = RetrievePage($dbi, gettext("RecentChanges"), $WikiPageStore);
337
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(); 
342       }
343
344       $now = time();
345       $today = date($dateformat, $now);
346
347       if (date($dateformat, $recentchanges["lastmodified"]) != $today) {
348          $isNewDay = TRUE;
349          $recentchanges["lastmodified"] = $now;
350       } else {
351          $isNewDay = FALSE;
352       }
353
354       $numlines = sizeof($recentchanges["content"]);
355       $newpage = array();
356       $k = 0;
357
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])) {
363             break;
364          } else {
365             $newpage[$k++] = $recentchanges["content"][$i];
366          }
367       }
368
369       // if it's a new date, insert it, else add the updated page's
370       // name to the array
371
372       if ($isNewDay) {
373          $newpage[$k++] = "____$today\r";
374          $newpage[$k++] = "\r";
375       } else {
376          $newpage[$k++] = $recentchanges["content"][$i++];
377       }
378       if($isnewpage) {
379          $newpage[$k++] = "\t* [$pagename] (new) ..... $remoteuser\r";
380       } else {
381          $diffurl = "$ScriptUrl?diff=" . rawurlencode($pagename);
382          $newpage[$k++] = "\t* [$pagename] ([diff|$diffurl]) ..... $remoteuser\r";
383       }
384
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])) {
390             continue;
391          } else {
392             $newpage[$k++] = $recentchanges["content"][$i];
393          }
394       }
395
396       $recentchanges["content"] = $newpage;
397
398       InsertPage($dbi, gettext("RecentChanges"), $recentchanges);
399    }
400
401
402
403    function ParseAndLink($bracketlink) {
404       global $dbi, $AllowedProtocols;
405
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.
408
409       // strip brackets and leading space
410       preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
411       $linkdata = $match[2];
412
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;
417          return $link;
418       }
419
420       // send back escaped ([[) bracket sets
421       if (preg_match("/^\[/", $linkdata)) {
422          $link['type'] = 'none';
423          $link['link'] = htmlspecialchars(substr($bracketlink, 1));
424          return $link;
425       }
426
427       // match the contents 
428       preg_match("/([^|]+)(\|)?([^|]+)?/", $linkdata, $matches);
429
430
431       // if $matches[3] is set, this is a link in the form of:
432       // [some link name | http://blippy.com/]
433
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>";
441          } else {
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>";
445          }
446          return $link;
447       }
448
449
450       // otherwise this is just a Wiki page like this: [page name]
451       // or a URL in brackets: [http://foo.com/]
452
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);
463             } else {
464                $link['type'] = 'url-simple';
465                $link['link'] = LinkURL($linkname);
466             }
467          } else {
468             $link['type'] = 'wiki-unknown';
469             $link['link'] = LinkUnknownWikiWord($linkname);
470          }
471
472          return $link;
473       }
474
475
476       $link['type'] = 'unknown';
477       $link['link'] = $bracketlink;
478       return $link;
479    }
480
481
482    function ExtractWikiPageLinks($content)
483    {
484       $wikilinks = array();
485
486       $numlines = count($content);
487       for($l = 0; $l < $numlines; $l++)
488       {
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]]++;
495
496             $brktlink = preg_quote($brktlinks[0][$i]);
497             $line = preg_replace("|$brktlink|", '', $line);
498          }
499
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]]++;
504             }
505          }
506       }
507
508       return $wikilinks;
509    }
510 ?>