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