]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/stdlib.php
"phpwiki:" protocol patch -- omitted stdlib.php in previous commit - *sigh*
[SourceForge/phpwiki.git] / lib / stdlib.php
1 <!-- $Id: stdlib.php,v 1.7 2000-10-31 19:23:03 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>" . gettext("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>";
53       $txt .= sprintf (gettext ("%d best incoming links:"), NUM_RELATED_PAGES);
54       $txt .= "</b>\n";
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), ";
59          }
60       }
61
62       $txt .= "\n<br><b>";
63       $txt .= sprintf (gettext ("%d best outgoing links:"), NUM_RELATED_PAGES);
64       $txt .= "</b>\n";
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), ";
70          }
71       }
72
73       $txt .= "\n<br><b>";
74       $txt .= sprintf (gettext ("%d most popular nearby:"), NUM_RELATED_PAGES);
75       $txt .= "</b>\n";
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), ";
80          }
81       }
82       
83       return $txt;
84    }
85
86    
87    function GeneratePage($template, $content, $name, $hash)
88    {
89       global $ScriptUrl, $AllowedProtocols, $templates;
90       global $datetimeformat, $dbi, $logo;
91
92       if (!is_array($hash))
93          unset($hash);
94
95       $page = join('', file($templates[$template]));
96       $page = str_replace('###', "#$FieldSeparator#", $page);
97
98       // valid for all pagetypes
99       $page = str_replace("#$FieldSeparator#SCRIPTURL#$FieldSeparator#",
100                         $ScriptUrl, $page);
101       $page = str_replace("#$FieldSeparator#PAGE#$FieldSeparator#",
102                         htmlspecialchars($name), $page);
103       $page = str_replace("#$FieldSeparator#ALLOWEDPROTOCOLS#$FieldSeparator#",
104                         $AllowedProtocols, $page);
105       $page = str_replace("#$FieldSeparator#LOGO#$FieldSeparator#",
106                         $logo, $page);
107
108       // invalid for messages (search results, error messages)
109       if ($template != 'MESSAGE') {
110          $page = str_replace("#$FieldSeparator#PAGEURL#$FieldSeparator#",
111                         rawurlencode($name), $page);
112          $page = str_replace("#$FieldSeparator#LASTMODIFIED#$FieldSeparator#",
113                         date($datetimeformat, $hash['lastmodified']), $page);
114          $page = str_replace("#$FieldSeparator#LASTAUTHOR#$FieldSeparator#",
115                         $hash['author'], $page);
116          $page = str_replace("#$FieldSeparator#VERSION#$FieldSeparator#",
117                         $hash['version'], $page);
118          if (strstr($page, "#$FieldSeparator#HITS#$FieldSeparator#")) {
119             $page = str_replace("#$FieldSeparator#HITS#$FieldSeparator#",
120                         GetHitCount($dbi, $name), $page);
121          }
122          if (strstr($page, "#$FieldSeparator#RELATEDPAGES#$FieldSeparator#")) {
123             $page = str_replace("#$FieldSeparator#RELATEDPAGES#$FieldSeparator#",
124                         LinkRelatedPages($dbi, $name), $page);
125          }
126       }
127
128       // valid only for EditLinks
129       if ($template == 'EDITLINKS') {
130          for ($i = 1; $i <= NUM_LINKS; $i++)
131             $page = str_replace("#$FieldSeparator#R$i#$FieldSeparator#",
132                         $hash['refs'][$i], $page);
133       }
134
135       if ($hash['copy']) {
136          $page = str_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#",
137                         '', $page);
138       } else {
139          $page = ereg_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#[^\n]*",
140                         '', $page);
141       }
142
143       $page = str_replace("#$FieldSeparator#CONTENT#$FieldSeparator#",
144                         $content, $page);
145       print $page;
146    }
147
148
149    function LinkExistingWikiWord($wikiword) {
150       global $ScriptUrl;
151       $enc_word = rawurlencode($wikiword);
152       $wikiword = htmlspecialchars($wikiword);
153       return "<a href=\"$ScriptUrl?$enc_word\">$wikiword</a>";
154    }
155
156    function LinkUnknownWikiWord($wikiword) {
157       global $ScriptUrl;
158       $enc_word = rawurlencode($wikiword);
159       $wikiword = htmlspecialchars($wikiword);
160       return "<u>$wikiword</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
161    }
162
163    function LinkURL($url) {
164       global $ScriptUrl;
165       if(ereg("[<>\"]", $url)) {
166          return "<b><u>BAD URL -- remove all of &lt;, &gt;, &quot;</u></b>";
167       }
168       $enc_url = htmlspecialchars($url);
169       return "<a href=\"$url\">$enc_url</a>";
170    }
171
172
173    function LinkImage($url, $alt="[External Image]") {
174       global $ScriptUrl;
175       if(ereg("[<>\"]", $url)) {
176          return "<b><u>BAD URL -- remove all of &lt;, &gt;, &quot;</u></b>";
177       }
178       return "<img src=\"$url\" ALT=\"$alt\">";
179    }
180
181    
182    function RenderQuickSearch($value = "") {
183       global $ScriptUrl;
184       return "<form action=\"$ScriptUrl\">\n" .
185              "<input type=text size=30 name=search value=\"$value\">\n" .
186              "<input type=submit value=\"". gettext("Search") .
187              "\"></form>\n";
188    }
189
190    function RenderFullSearch($value = "") {
191       global $ScriptUrl;
192       return "<form action=\"$ScriptUrl\">\n" .
193              "<input type=text size=30 name=full value=\"$value\">\n" .
194              "<input type=submit value=\"". gettext("Search") .
195              "\"></form>\n";
196    }
197
198    function RenderMostPopular() {
199       global $ScriptUrl, $dbi;
200       
201       $query = InitMostPopular($dbi, MOST_POPULAR_LIST_LENGTH);
202       $result = "<DL>\n";
203       while ($qhash = MostPopularNextMatch($dbi, $query)) {
204          $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
205       }
206       $result .= "</DL>\n";
207       
208       return $result;
209    }
210
211    // converts spaces to tabs
212    function CookSpaces($pagearray) {
213       return preg_replace("/ {3,8}/", "\t", $pagearray);
214    }
215
216
217    class Stack {
218       var $items;
219       var $size = 0;
220
221       function push($item) {
222          $this->items[$this->size] = $item;
223          $this->size++;
224          return true;
225       }  
226    
227       function pop() {
228          if ($this->size == 0) {
229             return false; // stack is empty
230          }  
231          $this->size--;
232          return $this->items[$this->size];
233       }  
234    
235       function cnt() {
236          return $this->size;
237       }  
238
239       function top() {
240          return $this->items[$this->size - 1];
241       }  
242
243    }  
244    // end class definition
245
246
247    // I couldn't move this to lib/config.php because it 
248    // wasn't declared yet.
249    $stack = new Stack;
250
251    /* 
252       Wiki HTML output can, at any given time, be in only one mode.
253       It will be something like Unordered List, Preformatted Text,
254       plain text etc. When we change modes we have to issue close tags
255       for one mode and start tags for another.
256    */
257
258    function SetHTMLOutputMode($tag, $tagdepth, $tabcount) {
259       global $stack;
260       $retvar = "";
261    
262       if ($tagdepth == SINGLE_DEPTH) {
263          if ($tabcount < $stack->cnt()) {
264             // there are fewer tabs than stack,
265             // reduce stack to that tab count
266             while ($stack->cnt() > $tabcount) {
267                $closetag = $stack->pop();
268                if ($closetag == false) {
269                   //echo "bounds error in tag stack";
270                   break;
271                }
272                $retvar .= "</$closetag>\n";
273             }
274
275             // if list type isn't the same,
276             // back up one more and push new tag
277             if ($tag != $stack->top()) {
278                $closetag = $stack->pop();
279                $retvar .= "</$closetag><$tag>\n";
280                $stack->push($tag);
281             }
282    
283          } elseif ($tabcount > $stack->cnt()) {
284             // we add the diff to the stack
285             // stack might be zero
286             while ($stack->cnt() < $tabcount) {
287                #echo "<$tag>\n";
288                $retvar .= "<$tag>\n";
289                $stack->push($tag);
290                if ($stack->cnt() > 10) {
291                   // arbitrarily limit tag nesting
292                   ExitWiki(gettext ("Stack bounds exceeded in SetHTMLOutputMode"));
293                }
294             }
295    
296          } else {
297             if ($tag == $stack->top()) {
298                return;
299             } else {
300                $closetag = $stack->pop();
301                #echo "</$closetag>\n";
302                #echo "<$tag>\n";
303                $retvar .= "</$closetag>\n";
304                $retvar .= "<$tag>\n";
305                $stack->push($tag);
306             }
307          }
308    
309       } elseif ($tagdepth == ZERO_DEPTH) {
310          // empty the stack for $depth == 0;
311          // what if the stack is empty?
312          if ($tag == $stack->top()) {
313             return;
314          }
315          while ($stack->cnt() > 0) {
316             $closetag = $stack->pop();
317             #echo "</$closetag>\n";
318             $retvar .= "</$closetag>\n";
319          }
320    
321          if ($tag) {
322             #echo "<$tag>\n";
323             $retvar .= "<$tag>\n";
324             $stack->push($tag);
325          }
326    
327       } else {
328          // error
329          ExitWiki ("Passed bad tag depth value in SetHTMLOutputMode");
330       }
331
332       return $retvar;
333
334    }
335    // end SetHTMLOutputMode
336
337
338
339    // The Recent Changes file is solely handled here
340    function UpdateRecentChanges($dbi, $pagename, $isnewpage) {
341
342       global $remoteuser; // this is set in the config
343       global $dateformat;
344       global $WikiPageStore;
345
346       $recentchanges = RetrievePage($dbi, gettext ("RecentChanges"), 
347         $WikiPageStore);
348
349       // this shouldn't be necessary, since PhpWiki loads 
350       // default pages if this is a new baby Wiki
351       if ($recentchanges == -1) {
352          $recentchanges = array(); 
353       }
354
355       $now = time();
356       $today = date($dateformat, $now);
357
358       if (date($dateformat, $recentchanges["lastmodified"]) != $today) {
359          $isNewDay = TRUE;
360          $recentchanges["lastmodified"] = $now;
361       } else {
362          $isNewDay = FALSE;
363       }
364
365       $numlines = sizeof($recentchanges["content"]);
366       $newpage = array();
367       $k = 0;
368
369       // scroll through the page to the first date and break
370       // dates are marked with "____" at the beginning of the line
371       for ($i = 0; $i < ($numlines + 1); $i++) {
372          if (preg_match("/^____/",
373                         $recentchanges["content"][$i])) {
374             break;
375          } else {
376             $newpage[$k++] = $recentchanges["content"][$i];
377          }
378       }
379
380       // if it's a new date, insert it, else add the updated page's
381       // name to the array
382
383       if ($isNewDay) {
384          $newpage[$k++] = "____$today\r";
385          $newpage[$k++] = "\r";
386       } else {
387          $newpage[$k++] = $recentchanges["content"][$i++];
388       }
389       if($isnewpage) {
390          $newpage[$k++] = "* [$pagename] (new) ..... $remoteuser\r";
391       } else {
392          $diffurl = "phpwiki:?diff=" . rawurlencode($pagename);
393          $newpage[$k++] = "* [$pagename] ([diff|$diffurl]) ..... $remoteuser\r";
394       }
395
396       // copy the rest of the page into the new array
397       $pagename = preg_quote($pagename);
398       for (; $i < ($numlines + 1); $i++) {
399          // skip previous entry for $pagename
400          if (preg_match("|\[$pagename\]|", $recentchanges["content"][$i])) {
401             continue;
402          } else {
403             $newpage[$k++] = $recentchanges["content"][$i];
404          }
405       }
406
407       $recentchanges["content"] = $newpage;
408
409       InsertPage($dbi, gettext ("RecentChanges"), $recentchanges);
410    }
411
412
413
414    function ParseAndLink($bracketlink) {
415       global $dbi, $ScriptUrl, $AllowedProtocols, $InlineImages;
416
417       // $bracketlink will start and end with brackets; in between
418       // will be either a page name, a URL or both separated by a pipe.
419
420       // strip brackets and leading space
421       preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
422       // match the contents 
423       preg_match("/([^|]+)(\|)?([^|]+)?/", $match[2], $matches);
424
425       // if $matches[3] is set, this is a link in the form of:
426       // [some link name | http://blippy.com/]
427
428       if (isset($matches[3])) {
429          $URL = trim($matches[3]);
430          $linkname = htmlspecialchars(trim($matches[1]));
431          // assert proper URL's
432          if (preg_match("#^($AllowedProtocols):#", $URL)) {
433             if (preg_match("/($InlineImages)$/i", $URL)) {
434                $link['type'] = 'image-named';
435                $link['link'] = LinkImage($URL, $linkname);
436             } else {
437                $link['type'] = 'url-named';
438                $link['link'] = "<a href=\"$URL\">$linkname</a>";
439             }
440          } elseif (preg_match("#^phpwiki:(.*)#", $URL, $match)) {
441             $link['type'] = 'url-wiki-named';
442             $link['link'] = "<a href=\"$ScriptUrl$match[1]\">$linkname</a>";
443          } else {
444             $link['type'] = 'url-bad';
445             $link['link'] = "<b><u>BAD URL -- links have to start with one" . 
446                    "of $AllowedProtocols followed by ':'</u></b>";
447          }
448          return $link;
449       }
450
451
452       // otherwise this is just a Wiki page like this: [page name]
453       // or a URL in brackets: [http://foo.com/]
454
455       if (isset($matches[1])) {
456          $linkname = trim($matches[1]);
457          if (IsWikiPage($dbi, $linkname)) {
458             $link['type'] = 'wiki';
459             $link['link'] = LinkExistingWikiWord($linkname);
460          } elseif (preg_match("#^($AllowedProtocols):#", $linkname)) {
461             // if it's an image, embed it; otherwise, it's a regular link
462             if (preg_match("/($InlineImages)$/i", $linkname)) {
463                $link['type'] = 'image-simple';
464                $link['link'] = LinkImage($linkname);
465             } else {
466                $link['type'] = 'url-simple';
467                $link['link'] = LinkURL($linkname);
468             }
469          } else {
470             $link['type'] = 'wiki-unknown';
471             $link['link'] = LinkUnknownWikiWord($linkname);
472          }
473          return $link;
474       }
475
476       $link['type'] = 'unknown';
477       $link['link'] = $bracketlink;
478       return $link;
479    }
480
481
482    function ExtractWikiPageLinks($content)
483    {
484       global $WikiNameRegexp;
485
486       $wikilinks = array();
487       $numlines = count($content);
488       for($l = 0; $l < $numlines; $l++)
489       {
490          $line = $content[$l];
491          $numBracketLinks = preg_match_all("/\[\s*(.+?)\s*\]/", $line, $brktlinks);
492          for ($i = 0; $i < $numBracketLinks; $i++) {
493             $link = ParseAndLink($brktlinks[0][$i]);
494             if($link['type'] == 'wiki' || $link['type'] == 'wiki-unknown')
495                $wikilinks[$brktlinks[1][$i]]++;
496
497             $brktlink = preg_quote($brktlinks[0][$i]);
498             $line = preg_replace("|$brktlink|", '', $line);
499          }
500
501          if (preg_match_all("/!?$WikiNameRegexp/", $line, $link)) {
502             for ($i = 0; $link[0][$i]; $i++) {
503                if($link[0][$i][0] <> '!')
504                   $wikilinks[$link[0][$i]]++;
505             }
506          }
507       }
508
509       return $wikilinks;
510    }      
511 ?>