]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/stdlib.php
fixed E_NOTICE warnings
[SourceForge/phpwiki.git] / lib / stdlib.php
1 <!-- $Id: stdlib.php,v 1.8 2000-11-01 11:31:41 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, $FieldSeparator;
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 (isset($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 = array();
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          if($this->size)
241             return $this->items[$this->size - 1];
242          else
243             return '';
244       }  
245
246    }  
247    // end class definition
248
249
250    // I couldn't move this to lib/config.php because it 
251    // wasn't declared yet.
252    $stack = new Stack;
253
254    /* 
255       Wiki HTML output can, at any given time, be in only one mode.
256       It will be something like Unordered List, Preformatted Text,
257       plain text etc. When we change modes we have to issue close tags
258       for one mode and start tags for another.
259    */
260
261    function SetHTMLOutputMode($tag, $tagdepth, $tabcount) {
262       global $stack;
263       $retvar = "";
264    
265       if ($tagdepth == SINGLE_DEPTH) {
266          if ($tabcount < $stack->cnt()) {
267             // there are fewer tabs than stack,
268             // reduce stack to that tab count
269             while ($stack->cnt() > $tabcount) {
270                $closetag = $stack->pop();
271                if ($closetag == false) {
272                   //echo "bounds error in tag stack";
273                   break;
274                }
275                $retvar .= "</$closetag>\n";
276             }
277
278             // if list type isn't the same,
279             // back up one more and push new tag
280             if ($tag != $stack->top()) {
281                $closetag = $stack->pop();
282                $retvar .= "</$closetag><$tag>\n";
283                $stack->push($tag);
284             }
285    
286          } elseif ($tabcount > $stack->cnt()) {
287             // we add the diff to the stack
288             // stack might be zero
289             while ($stack->cnt() < $tabcount) {
290                #echo "<$tag>\n";
291                $retvar .= "<$tag>\n";
292                $stack->push($tag);
293                if ($stack->cnt() > 10) {
294                   // arbitrarily limit tag nesting
295                   ExitWiki(gettext ("Stack bounds exceeded in SetHTMLOutputMode"));
296                }
297             }
298    
299          } else {
300             if ($tag == $stack->top()) {
301                return;
302             } else {
303                $closetag = $stack->pop();
304                #echo "</$closetag>\n";
305                #echo "<$tag>\n";
306                $retvar .= "</$closetag>\n";
307                $retvar .= "<$tag>\n";
308                $stack->push($tag);
309             }
310          }
311    
312       } elseif ($tagdepth == ZERO_DEPTH) {
313          // empty the stack for $depth == 0;
314          // what if the stack is empty?
315          if ($tag == $stack->top()) {
316             return;
317          }
318          while ($stack->cnt() > 0) {
319             $closetag = $stack->pop();
320             #echo "</$closetag>\n";
321             $retvar .= "</$closetag>\n";
322          }
323    
324          if ($tag) {
325             #echo "<$tag>\n";
326             $retvar .= "<$tag>\n";
327             $stack->push($tag);
328          }
329    
330       } else {
331          // error
332          ExitWiki ("Passed bad tag depth value in SetHTMLOutputMode");
333       }
334
335       return $retvar;
336
337    }
338    // end SetHTMLOutputMode
339
340
341
342    // The Recent Changes file is solely handled here
343    function UpdateRecentChanges($dbi, $pagename, $isnewpage) {
344
345       global $remoteuser; // this is set in the config
346       global $dateformat;
347       global $WikiPageStore;
348
349       $recentchanges = RetrievePage($dbi, gettext ("RecentChanges"), 
350         $WikiPageStore);
351
352       // this shouldn't be necessary, since PhpWiki loads 
353       // default pages if this is a new baby Wiki
354       if ($recentchanges == -1) {
355          $recentchanges = array(); 
356       }
357
358       $now = time();
359       $today = date($dateformat, $now);
360
361       if (date($dateformat, $recentchanges["lastmodified"]) != $today) {
362          $isNewDay = TRUE;
363          $recentchanges["lastmodified"] = $now;
364       } else {
365          $isNewDay = FALSE;
366       }
367
368       $numlines = sizeof($recentchanges["content"]);
369       $newpage = array();
370       $k = 0;
371
372       // scroll through the page to the first date and break
373       // dates are marked with "____" at the beginning of the line
374       for ($i = 0; $i < ($numlines + 1); $i++) {
375          if (preg_match("/^____/",
376                         $recentchanges["content"][$i])) {
377             break;
378          } else {
379             $newpage[$k++] = $recentchanges["content"][$i];
380          }
381       }
382
383       // if it's a new date, insert it, else add the updated page's
384       // name to the array
385
386       if ($isNewDay) {
387          $newpage[$k++] = "____$today\r";
388          $newpage[$k++] = "\r";
389       } else {
390          $newpage[$k++] = $recentchanges["content"][$i++];
391       }
392       if($isnewpage) {
393          $newpage[$k++] = "* [$pagename] (new) ..... $remoteuser\r";
394       } else {
395          $diffurl = "phpwiki:?diff=" . rawurlencode($pagename);
396          $newpage[$k++] = "* [$pagename] ([diff|$diffurl]) ..... $remoteuser\r";
397       }
398
399       // copy the rest of the page into the new array
400       $pagename = preg_quote($pagename);
401       for (; $i < $numlines; $i++) {
402          // skip previous entry for $pagename
403          if (preg_match("|\[$pagename\]|", $recentchanges["content"][$i])) {
404             continue;
405          } else {
406             $newpage[$k++] = $recentchanges["content"][$i];
407          }
408       }
409
410       $recentchanges["content"] = $newpage;
411
412       InsertPage($dbi, gettext ("RecentChanges"), $recentchanges);
413    }
414
415
416
417    function ParseAndLink($bracketlink) {
418       global $dbi, $ScriptUrl, $AllowedProtocols, $InlineImages;
419
420       // $bracketlink will start and end with brackets; in between
421       // will be either a page name, a URL or both separated by a pipe.
422
423       // strip brackets and leading space
424       preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
425       // match the contents 
426       preg_match("/([^|]+)(\|)?([^|]+)?/", $match[2], $matches);
427
428       // if $matches[3] is set, this is a link in the form of:
429       // [some link name | http://blippy.com/]
430
431       if (isset($matches[3])) {
432          $URL = trim($matches[3]);
433          $linkname = htmlspecialchars(trim($matches[1]));
434          // assert proper URL's
435          if (preg_match("#^($AllowedProtocols):#", $URL)) {
436             if (preg_match("/($InlineImages)$/i", $URL)) {
437                $link['type'] = 'image-named';
438                $link['link'] = LinkImage($URL, $linkname);
439             } else {
440                $link['type'] = 'url-named';
441                $link['link'] = "<a href=\"$URL\">$linkname</a>";
442             }
443          } elseif (preg_match("#^phpwiki:(.*)#", $URL, $match)) {
444             $link['type'] = 'url-wiki-named';
445             $link['link'] = "<a href=\"$ScriptUrl$match[1]\">$linkname</a>";
446          } else {
447             $link['type'] = 'url-bad';
448             $link['link'] = "<b><u>BAD URL -- links have to start with one" . 
449                    "of $AllowedProtocols followed by ':'</u></b>";
450          }
451          return $link;
452       }
453
454
455       // otherwise this is just a Wiki page like this: [page name]
456       // or a URL in brackets: [http://foo.com/]
457
458       if (isset($matches[1])) {
459          $linkname = trim($matches[1]);
460          if (IsWikiPage($dbi, $linkname)) {
461             $link['type'] = 'wiki';
462             $link['link'] = LinkExistingWikiWord($linkname);
463          } elseif (preg_match("#^($AllowedProtocols):#", $linkname)) {
464             // if it's an image, embed it; otherwise, it's a regular link
465             if (preg_match("/($InlineImages)$/i", $linkname)) {
466                $link['type'] = 'image-simple';
467                $link['link'] = LinkImage($linkname);
468             } else {
469                $link['type'] = 'url-simple';
470                $link['link'] = LinkURL($linkname);
471             }
472          } else {
473             $link['type'] = 'wiki-unknown';
474             $link['link'] = LinkUnknownWikiWord($linkname);
475          }
476          return $link;
477       }
478
479       $link['type'] = 'unknown';
480       $link['link'] = $bracketlink;
481       return $link;
482    }
483
484
485    function ExtractWikiPageLinks($content)
486    {
487       global $WikiNameRegexp;
488
489       $wikilinks = array();
490       $numlines = count($content);
491       for($l = 0; $l < $numlines; $l++)
492       {
493          $line = $content[$l];
494          $numBracketLinks = preg_match_all("/\[\s*(.+?)\s*\]/", $line, $brktlinks);
495          for ($i = 0; $i < $numBracketLinks; $i++) {
496             $link = ParseAndLink($brktlinks[0][$i]);
497             if($link['type'] == 'wiki' || $link['type'] == 'wiki-unknown')
498                $wikilinks[$brktlinks[1][$i]] = 1;
499
500             $brktlink = preg_quote($brktlinks[0][$i]);
501             $line = preg_replace("|$brktlink|", '', $line);
502          }
503
504          if (preg_match_all("/!?$WikiNameRegexp/", $line, $link)) {
505             for ($i = 0; isset($link[0][$i]); $i++) {
506                if($link[0][$i][0] <> '!')
507                   $wikilinks[$link[0][$i]] = 1;
508             }
509          }
510       }
511
512       return $wikilinks;
513    }      
514 ?>