]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/SystemInfo.php
New: Gracefully handle non-existant pages. Added copyleft;
[SourceForge/phpwiki.git] / lib / plugin / SystemInfo.php
1 <?php rcs_id('$Id: SystemInfo.php,v 1.4 2002-12-14 23:20:10 carstenklapp Exp $');
2 /**
3  * Usage: <?plugin SystemInfo all ?>
4  *        or <?plugin SystemInfo pagestats cachestats discspace hitstats ?> 
5  *        or <?plugin SystemInfo version ?> 
6  *        or <?plugin SystemInfo current_theme ?> 
7  *        or <?plugin SystemInfo PHPWIKI_DIR ?> 
8  *
9  * Provide access to phpwiki's lower level system information.
10  *   version, CHARSET, pagestats, SERVER_NAME, database, discspace, 
11  *   cachestats, userstats, linkstats, accessstats, hitstats, revisionstats,
12  *   interwikilinks, imageextensions, wikiwordregexp, availableplugins, downloadurl, ...
13  *
14  * In spirit to http://www.ecyrd.com/JSPWiki/SystemInfo.jsp
15  *
16  * Todo: Some calculations are heavy (~5-8 secs), so we should cache the result. 
17  *       In the page or with WikiPluginCached?
18  */
19 //require_once "lib/WikiPluginCached.php";
20
21 class WikiPlugin_SystemInfo
22 //extends WikiPluginCached
23 extends WikiPlugin
24 {
25     function getPluginType() {
26         return PLUGIN_CACHED_HTML;
27     }
28     function getName() {
29         return _("SystemInfo");
30     }
31
32     function getDescription() {
33         return _("Provides access to PhpWiki's lower level system information.");
34     }
35     function getExpire($dbi, $argarray, $request) {
36         return '+1800'; // 30 minutes
37     }
38     function getHtml($dbi, $argarray, $request) {
39         $loader = new WikiPluginLoader;
40         return $loader->expandPI('<?plugin SystemInfo '
41                                  . WikiPluginCached::glueArgs($argarray) // all 
42                                  . ' ?>',$request);         
43     }
44     /*
45     function getDefaultArguments() {
46         return array(
47                      'seperator' => ' ', // on multiple args
48                      );
49     }
50     */
51
52     function database() {
53         global $DBParams, $request;
54         $s  = _("db type:") . " {$DBParams['dbtype']}, ";
55         switch ($DBParams['dbtype']) {
56         case 'SQL':     // pear
57         case 'ADODB':
58             $dsn = $DBParams['dsn'];
59             $s .= _("db backend:") . " ";
60             $s .= ($DBParams['dbtype'] == 'SQL') ? 'PearDB' : 'ADODB';
61             if (preg_match('/^(\w+):/', $dsn, $m)) {
62                 $backend = $m[1];
63                 $s .= " $backend, ";
64             }
65             break;
66         case 'dba':
67             $s .= _("dba handler:") . " {$DBParams['dba_handler']}, ";
68             break;
69         case 'cvs':
70             // $s .= "cvs stuff: , ";
71             break;
72         case 'flatfile':
73             // $s .= "flatfile stuff: , ";
74             break;
75         }
76         // hack: suppress error when using sql, so no timeout
77         @$s .= _("timeout:") . " {$DBParams['timeout']}";
78         return $s;
79     }
80     function cachestats() {
81         global $DBParams, $request;
82         if (! defined('USECACHE') or !USECACHE)
83             return _("no cache used");
84         $dbi = $request->getDbh();
85         $cache = $dbi->_cache;
86         $s  = _("cached pagedata:") . " " . count($cache->_pagedata_cache);
87         $s .= ", " . _("cached versiondata:") . " " . count($cache->_versiondata_cache);
88         //$s .= ", glv size: " . count($cache->_glv_cache);
89         //$s .= ", cache hits: ?";
90         //$s .= ", cache misses: ?";
91         return $s;
92     }
93     function ExpireParams() {
94         global $ExpireParams;
95         $s  = sprintf(_("Keep up to %d major edits, but keep them no longer than %d days."), 
96                       $ExpireParams['major']['keep'], $ExpireParams['major']['max_age']);
97         $s .= sprintf(_(" Keep up to %d minor edits, but keep them no longer than %d days."), 
98                       $ExpireParams['minor']['keep'], $ExpireParams['minor']['max_age']);
99         $s .= sprintf(_(" Keep the latest contributions of the last %d authors up to %d days."), 
100                       $ExpireParams['author']['keep'], $ExpireParams['author']['max_age']);
101         $s .= sprintf(_(" Additionally, try to keep the latest contributions of all authors in the last %d days (even if there are more than %d of them,) but in no case keep more than %d unique author revisions."), 
102                       $ExpireParams['author']['min_age'], $ExpireParams['author']['keep'], $ExpireParams['author']['max_keep']);
103         return $s;
104     }
105     function pagestats() {
106         global $request;
107         $e = 0; $a = 0;
108         $dbi = $request->getDbh();
109         $include_empty = true;
110         $iter = $dbi->getAllPages($include_empty);
111         while ($page = $iter->next()) $e++;
112         $s  = sprintf(_("%d pages"), $e);
113         $include_empty = false;
114         $iter = $dbi->getAllPages($include_empty);
115         while ($page = $iter->next()) $a++;
116         $s  .= ", " . sprintf(_("%d not-empty pages"), $a);
117         // more bla....
118         // $s  .= ", " . sprintf(_("earliest page from %s"), $earliestdate);
119         // $s  .= ", " . sprintf(_("latest page from %s"), $latestdate);
120         // $s  .= ", " . sprintf(_("latest pagerevision from %s"), $latestrevdate);
121         return $s;
122     }
123     //What kind of link statistics?
124     //  total links in, total links out, mean links per page, ...
125     //  Any useful numbers similar to a VisualWiki interestmap? 
126     function linkstats() {
127         $s  = _("not yet");
128         return $s;
129     }
130     // number of homepages: easy
131     // number of anonymous users?
132     //   calc this from accesslog info?
133     // number of anonymous edits?
134     //   easy. related to the view/edit rate in accessstats. 
135     function userstats() {
136         global $request;
137         $dbi = $request->getDbh();
138         $h = 0;
139         $page_iter = $dbi->getAllPages(true);
140         while ($page = $page_iter->next()) {
141             if ($page->isUserPage(true)) // check if the admin is there. if not add him to the authusers.
142                 $h++;
143         }
144         $s  = sprintf(_("%d homepages"), $h);
145         // $s  .= ", " . sprintf(_("%d anonymous users"), $au); // ??
146         // $s  .= ", " . sprintf(_("%d anonymous edits"), $ae); // see recentchanges
147         // $s  .= ", " . sprintf(_("%d authenticated users"), $auth); // users with password set
148         // $s  .= ", " . sprintf(_("%d externally authenticated users"), $extauth); // query AuthDB?
149         return $s;
150     }
151     //only from logging info possible. = hitstats per time.
152     // total hits per day/month/year
153     // view/edit rate 
154     function accessstats() {
155         $s  = _("not yet");
156         return $s;
157     }
158     // only absolute numbers, not for any time interval. see accessstats
159     //  some useful number derived from the curve of the hit stats.
160     //  total, max, mean, median, stddev;
161     //  %d pages less than 3 hits (<10%)    <10% percent of the leastpopular
162     //  %d pages more than 100 hits (>90%)  >90% percent of the mostpopular
163     function hitstats() {
164         global $request;
165         $dbi = $request->getDbh();
166         $total = 0; $max = 0;
167         $hits = array();
168         $page_iter = $dbi->getAllPages(true);
169         while ($page = $page_iter->next()) {
170             if ($current = $page->getCurrentRevision() and (! $current->hasDefaultContents())) {
171                 $h = $page->get('hits');
172                 $hits[] = $h;
173                 $total += $h;
174                 $max = max($h,$max);
175             }
176         }
177         sort($hits);
178         reset($hits);
179         $n = count($hits);
180         $median_i = (int) $n / 2;
181         if (! ($n / 2))
182             $median = $hits[$median_i];
183         else
184             $median = $hits[$median_i];
185         $stddev = stddev(&$hits,$total);
186         
187         $s  = sprintf(_("total hits: %d"), $total);
188         $s .= ", " . sprintf(_("max: %d"), $max);
189         $s .= ", " . sprintf(_("mean: %2.3f"), $total / $n);
190         $s .= ", " . sprintf(_("median: %d"), $median);
191         $s .= ", " . sprintf(_("stddev: %2.3f"), $stddev);
192         $percentage = 10;
193         $mintreshold = $max * $percentage / 100.0;   // lower than 10% of the hits
194         reset($hits); $nmin = $hits[0] < $mintreshold ? 1 : 0;
195         while (next($hits) < $mintreshold)
196             $nmin++;
197         $maxtreshold = $max - $mintreshold; // more than 90% of the hits
198         end($hits); $nmax = 1;
199         while (prev($hits) > $maxtreshold)
200             $nmax++;
201         $s .= "; " . sprintf(_("%d pages with less than %d hits (<%d%%)."), $nmin, $mintreshold, $percentage);
202         $s .= " " . sprintf(_("%d page(s) with more than %d hits (>%d%%)."), $nmax, $maxtreshold, 100-$percentage);
203         return $s;
204     }
205     function revisionstats() {
206         global $request;
207         $dbi = $request->getDbh();
208         $total = 0; $max = 0;
209         $hits = array();
210         $page_iter = $dbi->getAllPages(true);
211         while ($page = $page_iter->next()) {
212             if ($current = $page->getCurrentRevision() and (! $current->hasDefaultContents())) {
213                 //$ma = $page->get('major');
214                 //$mi = $page->get('minor');
215                 ;
216             }
217         }
218         return 'not yet';
219     }
220     // size of databases/files/cvs are possible plus the known size of the app.
221     // Todo: cache this costly operation!
222     function discspace() {
223         global $DBParams;
224         $dir = PHPWIKI_DIR;
225         $appsize = `du -s $dir | cut -f1`;
226
227         if (in_array($DBParams['dbtype'],array('SQL','ADODB'))) {
228             $pagesize = 0;
229         } elseif ($DBParams['dbtype'] == 'dba') {
230             $pagesize = 0;
231             $dbdir = $DBParams['directory'];
232             if ($DBParams['dba_handler'] == 'db3')
233                 $pagesize = filesize($DBParams['directory']."/wiki_pagedb.db3") / 1024;
234             // if issubdirof($dbdir, $dir) $appsize -= $pagesize;
235         } else { // flatfile, cvs
236             $dbdir = $DBParams['directory'];
237             $pagesize = `du -s $dbdir`;
238             // if issubdirof($dbdir, $dir) $appsize -= $pagesize;
239         }
240         $s  = sprintf(_("Application size: %d Kb"), $appsize);
241         if ($pagesize)
242             $s  .= ", " . sprintf(_("Pagedata size: %d Kb", $pagesize));
243         return $s;
244     }
245
246     function inlineimages () {
247         return implode(' ',explode('|',$GLOBALS['InlineImages']));
248     }
249     function wikinameregexp () {
250         return $GLOBALS['WikiNameRegexp'];
251     }
252     function allowedprotocols () {
253         return implode(' ',explode('|',$GLOBALS['AllowedProtocols']));
254     }
255     function available_plugins () {
256         $fileset = new FileSet(FindFile('lib/plugin'),'*.php');
257         $list = $fileset->getFiles();
258         natcasesort($list);
259         reset($list);
260         return sprintf(_("Total %d plugins: "),count($list)) . 
261             implode(', ',array_map(create_function('$f','return substr($f,0,-4);'),$list));
262     }
263     function supported_languages () {
264         $available_languages = array('en');
265         $dir_root = PHPWIKI_DIR . '/locale/'; 
266         $dir = dir($dir_root);
267         if ($dir) {
268             while($entry = $dir->read()) {
269                 if (is_dir($dir_root.$entry) and (substr($entry,0,1) != '.') and 
270                     $entry != 'po' and $entry != 'CVS') {
271                     array_push($available_languages,$entry);
272                 }
273             }
274             $dir->close();
275         }
276         natcasesort($available_languages);
277
278         return sprintf(_("Total of %d languages: "),count($available_languages)) . 
279             implode(', ',$available_languages) . ". " .
280             sprintf(_("Current language: '%s'"), $GLOBALS['LANG']) .
281             ((DEFAULT_LANGUAGE != $GLOBALS['LANG']) 
282               ? ". " . sprintf(_("Default language: '%s'"), DEFAULT_LANGUAGE)
283               : '');
284     }
285
286     function supported_themes () {
287         global $Theme;
288         $available_themes = array(); 
289         $dir_root = PHPWIKI_DIR . '/themes/'; 
290         $dir = dir($dir_root);
291         if ($dir) {
292             while($entry = $dir->read()) {
293                 if (is_dir($dir_root.$entry) and (substr($entry,0,1) != '.') 
294                     and $entry!='CVS') {
295                     array_push($available_themes,$entry);
296                 }
297             }
298             $dir->close();
299         }
300         natcasesort($available_themes);
301         return sprintf(_("Total of %d themes: "),count($available_themes)) . 
302             implode(', ',$available_themes) . ". " .
303             sprintf(_("Current theme: '%s'"), $Theme->_name) . 
304             ((THEME != $Theme->_name)
305               ? ". " . sprintf(_("Default theme: '%s'"), THEME)
306               : '');
307     }
308
309
310     function call ($arg, &$availableargs) {
311         if (!empty($availableargs[$arg]))
312             return $availableargs[$arg]();
313         elseif (method_exists($this,$arg)) // any defined SystemInfo->method()system
314             return call_user_func_array(array(&$this, $arg),'');
315         elseif (defined($arg) and $arg != 'ADMIN_PASSWD') // any defined constant
316             return constant($arg);
317         else
318             return $this->error(sprintf(_("unknown argument '%s' to SystemInfo"),$arg));
319     }
320
321
322     function run($dbi, $argstr, $request) {
323         // don't parse argstr for name=value pairs. instead we use just 'name'
324         //$args = $this->getArgs($argstr, $request);
325         $args['seperator'] = ' ';
326         $availableargs = // name => callback + 0 args
327             array ('appname' => create_function('',"return 'PhpWiki';"),
328                    'version' => create_function('',"return sprintf('%s',PHPWIKI_VERSION);"),
329                    'LANG'    => create_function('','return $GLOBALS["LANG"];'),
330                    'LC_ALL'  => create_function('','return setlocale(LC_ALL, 0);'),
331                    'current_language' => create_function('','return $GLOBALS["LANG"];'),
332                    'system_language' => create_function('','return DEFAULT_LANGUAGE;'),
333                    'current_theme' => create_function('','return $GLOBALS["Theme"]->_name;'),
334                    'system_theme'  => create_function('','return THEME;'),
335                    // more here or as method.
336                    '' => create_function('',"return 'dummy';")
337                    );
338         // split the argument string by any number of commas or space characters,
339         // which include " ", \r, \t, \n and \f
340         $allargs = preg_split("/[\s,]+/",$argstr,-1,PREG_SPLIT_NO_EMPTY);
341         if (in_array('all',$allargs) or in_array('table',$allargs)) {
342             $allargs = array('appname'          => _("Application name"),
343                              'version'          => _("PhpWiki engine version"),
344                              'database'         => _("Database"),
345                              'cachestats'       => _("Cache statistics"),
346                              'pagestats'        => _("Page statistics"),
347                              //'revisionstats'          => _("Page revision statistics"),
348                              //'linkstats'      => _("Link statistics"),
349                              'userstats'        => _("User statistics"),
350                              //'accessstats'    => _("Access statistics"),
351                              'hitstats'         => _("Hit statistics"),
352 //                             'discspace'      => _("Harddisc usage"),
353                              'expireparams'     => _("Expiry parameters"),
354                              'wikinameregexp'   => _("Wikiname regexp"),
355                              'allowedprotocols' => _("Allowed protocols"),
356                              'inlineimages'     => _("Inline images"),
357                              'available_plugins'   => _("Available plugins"),
358                              'supported_languages' => _("Supported languages"),
359                              'supported_themes'    => _("Supported themes"),
360 //                           '' => _(""),
361                              '' => ""
362                              );
363             $table = HTML::table(array('border' => 1,'cellspacing' => 3,'cellpadding' => 3));
364             foreach ($allargs as $arg => $desc) {
365                 if (!$arg) continue;
366                 if (!$desc) $desc = _($arg);
367                 $table->pushContent(HTML::tr(HTML::td(HTML::strong($desc . ':')),
368                                              HTML::td(HTML($this->call($arg,&$availableargs)))));
369             }
370             return $table;
371         } else {
372             $output = '';
373             foreach ($allargs as $arg) {
374                 $o = $this->call($arg,&$availableargs);
375                 if (is_object($o)) return $o;
376                 else $output .= ($o . $args['seperator']);
377             }
378             // if more than one arg, remove the trailing seperator
379             if ($output) $output = substr($output,0,- strlen($args['seperator']));
380             return HTML($output);
381         }
382     }
383 }
384
385 /* // autolisp stdlib
386 ;;; Median of the sorted list of numbers. 50% is above and 50% below
387 ;;; "center of a distribution"
388 ;;; Ex: (std-median (std-make-list 100 std-%random)) => 0.5 +- epsilon
389 ;;;     (std-median (std-make-list 100 (lambda () (std-random 10))))
390 ;;;       => 4.0-5.0 [0..9]
391 ;;;     (std-median (std-make-list 99  (lambda () (std-random 10))))
392 ;;;       => 4-5
393 ;;;     (std-median '(0 0 2 4 12))      => 2
394 ;;;     (std-median '(0 0 4 12))        => 2.0
395 (defun STD-MEDIAN (numlst / l)
396   (setq numlst (std-sort numlst '<))            ; don't remove duplicates
397   (if (= 0 (rem (setq l (length numlst)) 2))    ; if even length
398     (* 0.5 (+ (nth (/ l 2) numlst)              ; force float!
399               (nth (1- (/ l 2)) numlst)))       ; fixed by Serge Pashkov
400     (nth (/ l 2) numlst)))
401
402 */
403 function median($hits) {
404     sort($hits);
405     reset($hits);
406     $n = count($hits);
407     $median = (int) $n / 2;
408     if (! ($n % 2)) // proper rounding on even length
409         return ($hits[$median] + $hits[$median-1]) * 0.5;
410     else
411         return $hits[$median];
412 }
413
414 function rsum($a, $b) {
415     $a += $b;
416     return $a;
417 }
418 function mean(&$hits,$total=false) {
419     $n = count($hits);
420     if (!$total) $total = array_reduce($hits,'rsum');
421     return (float) $total / ($n * 1.0);
422 }
423 function gensym($prefix = "_gensym") {
424     $i = 0;
425     while (isset($GLOBALS[$prefix.$i])) $i++;
426     return $prefix.$i;
427 }
428
429 /* // autolisp stdlib
430 (defun STD-STANDARD-DEVIATION (numlst / n _dev_m r)
431   (setq n      (length numlst)
432         _dev_m (std-mean numlst)
433         r      (mapcar (function (lambda (x) (std-sqr (- x _dev_m)))) numlst))
434   (sqrt (* (std-mean r) (/ n (float (- n 1))))))
435 */
436 /*
437 function stddev(&$hits,$total=false) {
438     $n = count($hits);
439     if (!$total) $total = array_reduce($hits,'rsum');
440     $mean = gensym("_mean");
441     $GLOBALS[$mean] = $total / $n;
442     $cb = "global ${$mean}; return (\$i-${$mean})*(\$i-${$mean});";
443     $r = array_map(create_function('$i',"global ${$mean}; return (\$i-${$mean})*(\$i-${$mean});"),$hits);
444     unset($GLOBALS[$mean]);
445     return (float) sqrt(mean($r,$total) * ($n / (float)($n -1)));
446 }
447 */
448 function stddev(&$hits,$total=false) {
449     $n = count($hits);
450     if (!$total) $total = array_reduce($hits,'rsum');
451     $GLOBALS['mean'] = $total / $n;
452     $r = array_map(create_function('$i','global $mean; return ($i-$mean)*($i-$mean);'),$hits);
453     unset($GLOBALS['mean']);
454     return (float) sqrt(mean($r,$total) * ($n / (float)($n -1)));
455 }
456
457 // Local Variables:
458 // mode: php
459 // tab-width: 8
460 // c-basic-offset: 4
461 // c-hanging-comment-ender-p: nil
462 // indent-tabs-mode: nil
463 // End:
464 ?>