]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - wiki_stdlib.php3
New function rcs_id(): we don't want any garbage emitted when generating zip files.
[SourceForge/phpwiki.git] / wiki_stdlib.php3
1 <!-- $Id: wiki_stdlib.php3,v 1.22 2000-07-05 14:52:04 ahollosi Exp $ -->
2 <?
3    /*
4       Standard functions for Wiki functionality
5          GeneratePage($template, $content, $name, $hash)
6          LinkExistingWikiWord($wikiword) 
7          LinkUnknownWikiWord($wikiword) 
8          LinkURL($url)
9          RenderQuickSearch() 
10          RenderFullSearch() 
11          RenderMostPopular()
12          CookSpaces($pagearray) 
13          class Stack
14          SetHTMLOutputMode($newmode, $depth)
15          UpdateRecentChanges($dbi, $pagename, $isnewpage) 
16          SaveCopyToArchive($pagename, $pagehash) 
17          ParseAndLink($bracketlink)
18    */
19
20
21    function GeneratePage($template, $content, $name, $hash)
22    {
23       global $ScriptUrl, $AllowedProtocols, $templates;
24       global $datetimeformat, $dbi, $logo;
25
26       if (!is_array($hash))
27          unset($hash);
28
29       $page = join('', file($templates[$template]));
30       $page = str_replace('###', "#$FieldSeparator#", $page);
31
32       // valid for all pagetypes
33       $page = str_replace("#$FieldSeparator#SCRIPTURL#$FieldSeparator#",
34                         $ScriptUrl, $page);
35       $page = str_replace("#$FieldSeparator#PAGE#$FieldSeparator#",
36                         htmlspecialchars($name), $page);
37       $page = str_replace("#$FieldSeparator#ALLOWEDPROTOCOLS#$FieldSeparator#",
38                         $AllowedProtocols, $page);
39       $page = str_replace("#$FieldSeparator#LOGO#$FieldSeparator#",
40                         $logo, $page);
41
42       // invalid for messages (search results, error messages)
43       if ($template != 'MESSAGE') {
44          $page = str_replace("#$FieldSeparator#PAGEURL#$FieldSeparator#",
45                         rawurlencode($name), $page);
46          $page = str_replace("#$FieldSeparator#LASTMODIFIED#$FieldSeparator#",
47                         date($datetimeformat, $hash['lastmodified']), $page);
48          $page = str_replace("#$FieldSeparator#LASTAUTHOR#$FieldSeparator#",
49                         $hash['author'], $page);
50          $page = str_replace("#$FieldSeparator#VERSION#$FieldSeparator#",
51                         $hash['version'], $page);
52          if (strstr($page, "#$FieldSeparator#HITS#$FieldSeparator#")) {
53             $page = str_replace("#$FieldSeparator#HITS#$FieldSeparator#",
54                         GetHitCount($dbi, $name), $page);
55          }
56       }
57
58       // valid only for EditLinks
59       if ($template == 'EDITLINKS') {
60          for ($i = 1; $i <= NUM_LINKS; $i++)
61             $page = str_replace("#$FieldSeparator#R$i#$FieldSeparator#",
62                         $hash['refs'][$i], $page);
63       }
64
65       if ($hash['copy']) {
66          $page = str_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#",
67                         '', $page);
68       } else {
69          $page = ereg_replace("#$FieldSeparator#IFCOPY#$FieldSeparator#[^\n]*",
70                         '', $page);
71       }
72
73       $page = str_replace("#$FieldSeparator#CONTENT#$FieldSeparator#",
74                         $content, $page);
75       print $page;
76    }
77
78
79    function LinkExistingWikiWord($wikiword) {
80       global $ScriptUrl;
81       $enc_word = rawurlencode($wikiword);
82       $wikiword = htmlspecialchars($wikiword);
83       return "<a href=\"$ScriptUrl?$enc_word\">$wikiword</a>";
84    }
85
86    function LinkUnknownWikiWord($wikiword) {
87       global $ScriptUrl;
88       $enc_word = rawurlencode($wikiword);
89       $wikiword = htmlspecialchars($wikiword);
90       return "<u>$wikiword</u><a href=\"$ScriptUrl?edit=$enc_word\">?</a>";
91    }
92
93    function LinkURL($url) {
94       global $ScriptUrl;
95       if(ereg("[<>\"]", $url)) {
96          return "<b><u>BAD URL -- remove all of &lt;, &gt;, &quot;</u></b>";
97       }
98       $enc_url = htmlspecialchars($url);
99       return "<a href=\"$url\">$enc_url</a>";
100    }
101
102    
103    function RenderQuickSearch() {
104       global $value, $ScriptUrl;
105       $formtext = "<form action='$ScriptUrl'>\n<input type='text' size='40' name='search' value='$value'>\n</form>\n";
106       return $formtext;
107    }
108
109    function RenderFullSearch() {
110       global $value, $ScriptUrl;
111       $formtext = "<form action='$ScriptUrl'>\n<input type='text' size='40' name='full' value='$value'>\n</form>\n";
112       return $formtext;
113    }
114
115    function RenderMostPopular() {
116       global $ScriptUrl, $dbi;
117       
118       $query = InitMostPopular($dbi, 20);
119       $result = "<DL>\n";
120       while ($qhash = MostPopularNextMatch($dbi, $query)) {
121          $result .= "<DD>$qhash[hits] ... " . LinkExistingWikiWord($qhash['pagename']) . "\n";
122       }
123       $result .= "</DL>\n";
124       
125       return $result;
126    }
127
128    // converts spaces to tabs
129    function CookSpaces($pagearray) {
130       return preg_replace("/ {3,8}/", "\t", $pagearray);
131    }
132
133
134    class Stack {
135       var $items;
136       var $size = 0;
137
138       function push($item) {
139          $this->items[$this->size] = $item;
140          $this->size++;
141          return true;
142       }  
143    
144       function pop() {
145          if ($this->size == 0) {
146             return false; // stack is empty
147          }  
148          $this->size--;
149          return $this->items[$this->size];
150       }  
151    
152       function cnt() {
153          return $this->size;
154       }  
155
156       function top() {
157          return $this->items[$this->size - 1];
158       }  
159
160    }  
161    // end class definition
162
163
164    // I couldn't move this to wiki_config.php3 because it 
165    // wasn't declared yet.
166    $stack = new Stack;
167
168    /* 
169       Wiki HTML output can, at any given time, be in only one mode.
170       It will be something like Unordered List, Preformatted Text,
171       plain text etc. When we change modes we have to issue close tags
172       for one mode and start tags for another.
173    */
174
175    function SetHTMLOutputMode($tag, $tagdepth, $tabcount) {
176       global $stack;
177       $retvar = "";
178    
179       if ($tagdepth == SINGLE_DEPTH) {
180          if ($tabcount < $stack->cnt()) {
181             // there are fewer tabs than stack,
182             // reduce stack to that tab count
183             while ($stack->cnt() > $tabcount) {
184                $closetag = $stack->pop();
185                if ($closetag == false) {
186                   //echo "bounds error in tag stack";
187                   break;
188                }
189                $retvar .= "</$closetag>\n";
190             }
191
192             // if list type isn't the same,
193             // back up one more and push new tag
194             if ($tag != $stack->top()) {
195                $closetag = $stack->pop();
196                $retvar .= "</$closetag><$tag>\n";
197                $stack->push($tag);
198             }
199    
200          } elseif ($tabcount > $stack->cnt()) {
201             // we add the diff to the stack
202             // stack might be zero
203             while ($stack->cnt() < $tabcount) {
204                #echo "<$tag>\n";
205                $retvar .= "<$tag>\n";
206                $stack->push($tag);
207                if ($stack->cnt() > 10) {
208                   // arbitrarily limit tag nesting
209                   echo "Stack bounds exceeded in SetHTMLOutputMode\n";
210                   exit();
211                }
212             }
213    
214          } else {
215             if ($tag == $stack->top()) {
216                return;
217             } else {
218                $closetag = $stack->pop();
219                #echo "</$closetag>\n";
220                #echo "<$tag>\n";
221                $retvar .= "</$closetag>\n";
222                $retvar .= "<$tag>\n";
223                $stack->push($tag);
224             }
225          }
226    
227       } elseif ($tagdepth == ZERO_DEPTH) {
228          // empty the stack for $depth == 0;
229          // what if the stack is empty?
230          if ($tag == $stack->top()) {
231             return;
232          }
233          while ($stack->cnt() > 0) {
234             $closetag = $stack->pop();
235             #echo "</$closetag>\n";
236             $retvar .= "</$closetag>\n";
237          }
238    
239          if ($tag) {
240             #echo "<$tag>\n";
241             $retvar .= "<$tag>\n";
242             $stack->push($tag);
243          }
244    
245       } else {
246          // error
247          echo "Passed bad tag depth value in SetHTMLOutputMode\n";
248          exit();
249       }
250
251       return $retvar;
252
253    }
254    // end SetHTMLOutputMode
255
256
257
258    // The Recent Changes file is solely handled here
259    function UpdateRecentChanges($dbi, $pagename, $isnewpage) {
260
261       global $remoteuser; // this is set in the config
262       global $dateformat;
263
264       $recentchanges = RetrievePage($dbi, "RecentChanges");
265
266       // this shouldn't be necessary, since PhpWiki loads 
267       // default pages if this is a new baby Wiki
268       if ($recentchanges == -1) {
269          $recentchanges = array(); 
270       }
271
272       $now = time();
273       $today = date($dateformat, $now);
274
275       if (date($dateformat, $recentchanges["lastmodified"]) != $today) {
276          $isNewDay = TRUE;
277          $recentchanges["lastmodified"] = $now;
278       } else {
279          $isNewDay = FALSE;
280       }
281
282       $numlines = sizeof($recentchanges["content"]);
283       $newpage = array();
284       $k = 0;
285
286       // scroll through the page to the first date and break
287       // dates are marked with "____" at the beginning of the line
288       for ($i = 0; $i < ($numlines + 1); $i++) {
289          if (preg_match("/^____/",
290                         $recentchanges["content"][$i])) {
291             break;
292          } else {
293             $newpage[$k++] = $recentchanges["content"][$i];
294          }
295       }
296
297       // if it's a new date, insert it, else add the updated page's
298       // name to the array
299
300       if ($isNewDay) {
301          $newpage[$k++] = "____$today\r";
302          $newpage[$k++] = "\r";
303       } else {
304          $newpage[$k++] = $recentchanges["content"][$i++];
305       }
306       if($isnewpage) {
307          $newpage[$k++] = "\t* [$pagename] (new) ..... $remoteuser\r";
308       } else {
309          $newpage[$k++] = "\t* [$pagename] ..... $remoteuser\r";
310       }
311
312       // copy the rest of the page into the new array
313       $pagename = preg_quote($pagename);
314       for (; $i < ($numlines + 1); $i++) {
315          // skip previous entry for $pagename
316          if (preg_match("|\[$pagename\]|", $recentchanges["content"][$i])) {
317             continue;
318          } else {
319             $newpage[$k++] = $recentchanges["content"][$i];
320          }
321       }
322
323       $recentchanges["content"] = $newpage;
324
325       InsertPage($dbi, "RecentChanges", $recentchanges);
326    }
327
328
329    // for archiving pages to a seperate dbm
330    function SaveCopyToArchive($pagename, $pagehash) {
331       global $ArchiveDataBase;
332
333       $adbi = OpenDataBase($ArchiveDataBase);
334       $newpagename = $pagename;
335       InsertPage($adbi, $newpagename, $pagehash);
336    }
337
338
339    function ParseAndLink($bracketlink) {
340       global $dbi, $AllowedProtocols;
341
342       // $bracketlink will start and end with brackets; in between
343       // will be either a page name, a URL or both seperated by a pipe.
344
345       // strip brackets and leading space
346       preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
347       $linkdata = $match[2];
348
349       // send back links that are only numbers (they are references)
350       if (preg_match("/^\d+$/", $linkdata)) {
351          return $bracketlink;
352       }
353
354       // send back escaped ([[) bracket sets
355       if (preg_match("/^\[/", $linkdata)) {
356          return htmlspecialchars(substr($bracketlink, 1));
357       }
358
359       // match the contents 
360       preg_match("/([^|]+)(\|)?([^|]+)?/", $linkdata, $matches);
361
362       if (isset($matches[3])) {
363          $URL = trim($matches[3]);
364          $linkname = htmlspecialchars(trim($matches[1]));
365          // assert proper URL's
366          if (preg_match("#^($AllowedProtocols):#", $URL)) {
367             return "<a href=\"$URL\">$linkname</a>";
368          } else {
369             return "<b><u>BAD URL -- links have to start with one of " .                                                "$AllowedProtocols followed by ':'</u></b>";
370          }
371       }
372
373       if (isset($matches[1])) {
374          $linkname = trim($matches[1]);
375          if (IsWikiPage($dbi, $linkname)) {
376             return LinkExistingWikiWord($linkname);
377          } elseif (preg_match("#^($AllowedProtocols):#", $linkname)) {
378             return LinkURL($linkname);
379          } else {
380             return LinkUnknownWikiWord($linkname);
381          }
382       }
383
384       return $bracketlink;
385
386    }
387
388 ?>