]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/SystemInfo.php
Connect the rest of PhpWiki to the IniConfig system. Also the keyword regular expres...
[SourceForge/phpwiki.git] / lib / plugin / SystemInfo.php
1 <?php // -*-php-*-
2 rcs_id('$Id: SystemInfo.php,v 1.14 2004-04-19 23:13:04 zorloc Exp $');
3 /**
4  Copyright (C) 1999, 2000, 2001, 2002 $ThePhpWikiProgrammingTeam
5
6  This file is part of PhpWiki.
7
8  PhpWiki is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  PhpWiki is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with PhpWiki; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 /**
24  * Usage: <?plugin SystemInfo all ?>
25  *        or <?plugin SystemInfo pagestats cachestats discspace hitstats ?>
26  *        or <?plugin SystemInfo version ?>
27  *        or <?plugin SystemInfo current_theme ?>
28  *        or <?plugin SystemInfo PHPWIKI_DIR ?>
29  *
30  * Provide access to phpwiki's lower level system information.
31  *
32  *   version, charset, pagestats, SERVER_NAME, database, discspace,
33  *   cachestats, userstats, linkstats, accessstats, hitstats,
34  *   revisionstats, interwikilinks, imageextensions, wikiwordregexp,
35  *   availableplugins, downloadurl, ...
36  *
37  * In spirit to http://www.ecyrd.com/JSPWiki/SystemInfo.jsp
38  *
39  * Todo: Some calculations are heavy (~5-8 secs), so we should cache
40  *       the result. In the page or with WikiPluginCached?
41  */
42 //require_once "lib/WikiPluginCached.php";
43
44 class WikiPlugin_SystemInfo
45 //extends WikiPluginCached
46 extends WikiPlugin
47 {
48     function getPluginType() {
49         return PLUGIN_CACHED_HTML;
50     }
51     function getName() {
52         return _("SystemInfo");
53     }
54
55     function getDescription() {
56         return _("Provides access to PhpWiki's lower level system information.");
57     }
58
59     function getVersion() {
60         return preg_replace("/[Revision: $]/", '',
61                             "\$Revision: 1.14 $");
62     }
63
64     function getExpire($dbi, $argarray, $request) {
65         return '+1800'; // 30 minutes
66     }
67     function getHtml($dbi, $argarray, $request, $basepage) {
68         $loader = new WikiPluginLoader;
69         return $loader->expandPI('<?plugin SystemInfo '
70                                  . WikiPluginCached::glueArgs($argarray) // all
71                                  . ' ?>', $request, $this, $basepage);
72     }
73     /*
74     function getDefaultArguments() {
75         return array(
76                      'seperator' => ' ', // on multiple args
77                      );
78     }
79     */
80
81     function database() {
82         global $DBParams, $request;
83         $s  = _("db type:") . " {$DBParams['dbtype']}, ";
84         switch ($DBParams['dbtype']) {
85         case 'SQL':     // pear
86         case 'ADODB':
87             $dsn = $DBParams['dsn'];
88             $s .= _("db backend:") . " ";
89             $s .= ($DBParams['dbtype'] == 'SQL') ? 'PearDB' : 'ADODB';
90             if (preg_match('/^(\w+):/', $dsn, $m)) {
91                 $backend = $m[1];
92                 $s .= " $backend, ";
93             }
94             break;
95         case 'dba':
96             $s .= _("dba handler:") . " {$DBParams['dba_handler']}, ";
97             break;
98         case 'cvs':
99             // $s .= "cvs stuff: , ";
100             break;
101         case 'flatfile':
102             // $s .= "flatfile stuff: , ";
103             break;
104         }
105         // hack: suppress error when using sql, so no timeout
106         @$s .= _("timeout:") . " {$DBParams['timeout']}";
107         return $s;
108     }
109     function cachestats() {
110         global $DBParams, $request;
111         if (! defined('USECACHE') or !USECACHE)
112             return _("no cache used");
113         $dbi = $request->getDbh();
114         $cache = $dbi->_cache;
115         $s  = _("cached pagedata:") . " " . count($cache->_pagedata_cache);
116         $s .= ", " . _("cached versiondata:");
117         $s .= " " . count($cache->_versiondata_cache);
118         //$s .= ", glv size: " . count($cache->_glv_cache);
119         //$s .= ", cache hits: ?";
120         //$s .= ", cache misses: ?";
121         return $s;
122     }
123     function ExpireParams() {
124         global $ExpireParams;
125         $s  = sprintf(_("Keep up to %d major edits, but keep them no longer than %d days."),
126                       $ExpireParams['major']['keep'],
127                       $ExpireParams['major']['max_age']);
128         $s .= sprintf(_(" Keep up to %d minor edits, but keep them no longer than %d days."),
129                       $ExpireParams['minor']['keep'],
130                       $ExpireParams['minor']['max_age']);
131         $s .= sprintf(_(" Keep the latest contributions of the last %d authors up to %d days."),
132                       $ExpireParams['author']['keep'], $ExpireParams['author']['max_age']);
133         $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."),
134                       $ExpireParams['author']['min_age'],
135                       $ExpireParams['author']['keep'],
136                       $ExpireParams['author']['max_keep']);
137         return $s;
138     }
139     function pagestats() {
140         global $request;
141         $e = 0;
142         $a = 0;
143         $dbi = $request->getDbh();
144         $include_empty = true;
145         $iter = $dbi->getAllPages($include_empty);
146         while ($page = $iter->next())
147             $e++;
148         $s  = sprintf(_("%d pages"), $e);
149         $include_empty = false;
150         $iter = $dbi->getAllPages($include_empty);
151         while ($page = $iter->next())
152             $a++;
153         $s  .= ", " . sprintf(_("%d not-empty pages"), $a);
154         // more bla....
155         // $s  .= ", " . sprintf(_("earliest page from %s"), $earliestdate);
156         // $s  .= ", " . sprintf(_("latest page from %s"), $latestdate);
157         // $s  .= ", " . sprintf(_("latest pagerevision from %s"), $latestrevdate);
158         return $s;
159     }
160     //What kind of link statistics?
161     //  total links in, total links out, mean links per page, ...
162     //  Any useful numbers similar to a VisualWiki interestmap?
163     function linkstats() {
164         $s  = _("not yet");
165         return $s;
166     }
167     // number of homepages: easy
168     // number of anonymous users?
169     //   calc this from accesslog info?
170     // number of anonymous edits?
171     //   easy. related to the view/edit rate in accessstats.
172     function userstats() {
173         global $request;
174         $dbi = $request->getDbh();
175         $h = 0;
176         $page_iter = $dbi->getAllPages(true);
177         while ($page = $page_iter->next()) {
178             if ($page->isUserPage(true)) // check if the admin is there. if not add him to the authusers.
179                 $h++;
180         }
181         $s  = sprintf(_("%d homepages"), $h);
182         // $s  .= ", " . sprintf(_("%d anonymous users"), $au); // ??
183         // $s  .= ", " . sprintf(_("%d anonymous edits"), $ae); // see recentchanges
184         // $s  .= ", " . sprintf(_("%d authenticated users"), $auth); // users with password set
185         // $s  .= ", " . sprintf(_("%d externally authenticated users"), $extauth); // query AuthDB?
186         return $s;
187     }
188     //only from logging info possible. = hitstats per time.
189     // total hits per day/month/year
190     // view/edit rate
191     function accessstats() {
192         $s  = _("not yet");
193         return $s;
194     }
195     // only absolute numbers, not for any time interval. see accessstats
196     //  some useful number derived from the curve of the hit stats.
197     //  total, max, mean, median, stddev;
198     //  %d pages less than 3 hits (<10%)    <10% percent of the leastpopular
199     //  %d pages more than 100 hits (>90%)  >90% percent of the mostpopular
200     function hitstats() {
201         global $request;
202         $dbi = $request->getDbh();
203         $total = 0;
204         $max = 0;
205         $hits = array();
206         $page_iter = $dbi->getAllPages(true);
207         while ($page = $page_iter->next()) {
208             if (($current = $page->getCurrentRevision())
209                 && (! $current->hasDefaultContents())) {
210                 $h = $page->get('hits');
211                 $hits[] = $h;
212                 $total += $h;
213                 $max = max($h, $max);
214             }
215         }
216         sort($hits);
217         reset($hits);
218         $n = count($hits);
219         $median_i = (int) $n / 2;
220         if (! ($n / 2))
221             $median = $hits[$median_i];
222         else
223             $median = $hits[$median_i];
224         $stddev = stddev($hits, $total);
225
226         $s  = sprintf(_("total hits: %d"), $total);
227         $s .= ", " . sprintf(_("max: %d"), $max);
228         $s .= ", " . sprintf(_("mean: %2.3f"), $total / $n);
229         $s .= ", " . sprintf(_("median: %d"), $median);
230         $s .= ", " . sprintf(_("stddev: %2.3f"), $stddev);
231         $percentage = 10;
232         $mintreshold = $max * $percentage / 100.0;   // lower than 10% of the hits
233         reset($hits);
234         $nmin = $hits[0] < $mintreshold ? 1 : 0;
235         while (next($hits) < $mintreshold)
236             $nmin++;
237         $maxtreshold = $max - $mintreshold; // more than 90% of the hits
238         end($hits);
239         $nmax = 1;
240         while (prev($hits) > $maxtreshold)
241             $nmax++;
242         $s .= "; " . sprintf(_("%d pages with less than %d hits (<%d%%)."),
243                              $nmin, $mintreshold, $percentage);
244         $s .= " " . sprintf(_("%d page(s) with more than %d hits (>%d%%)."),
245                             $nmax, $maxtreshold, 100 - $percentage);
246         return $s;
247     }
248     function revisionstats() {
249         global $request;
250         $dbi = $request->getDbh();
251         $total = 0;
252         $max = 0;
253         $hits = array();
254         $page_iter = $dbi->getAllPages(true);
255         while ($page = $page_iter->next()) {
256             if ($current = $page->getCurrentRevision()
257                 && (! $current->hasDefaultContents())) {
258                 //$ma = $page->get('major');
259                 //$mi = $page->get('minor');
260                 ;
261             }
262         }
263         return 'not yet';
264     }
265     // size of databases/files/cvs are possible plus the known size of the app.
266     // Todo: cache this costly operation!
267     function discspace() {
268         global $DBParams;
269         $dir = defined('PHPWIKI_DIR') ? PHPWIKI_DIR : '.';
270         $appsize = `du -s $dir | cut -f1`;
271
272         if (in_array($DBParams['dbtype'], array('SQL', 'ADODB'))) {
273             $pagesize = 0;
274         } elseif ($DBParams['dbtype'] == 'dba') {
275             $pagesize = 0;
276             $dbdir = $DBParams['directory'];
277             if ($DBParams['dba_handler'] == 'db3')
278                 $pagesize = filesize($DBParams['directory']
279                                      . "/wiki_pagedb.db3") / 1024;
280             // if issubdirof($dbdir, $dir) $appsize -= $pagesize;
281         } else { // flatfile, cvs
282             $dbdir = $DBParams['directory'];
283             $pagesize = `du -s $dbdir`;
284             // if issubdirof($dbdir, $dir) $appsize -= $pagesize;
285         }
286         $s  = sprintf(_("Application size: %d Kb"), $appsize);
287         if ($pagesize)
288             $s  .= ", " . sprintf(_("Pagedata size: %d Kb", $pagesize));
289         return $s;
290     }
291
292     function inlineimages () {
293         return implode(' ', explode('|', INLINE_IMAGES));
294     }
295     function wikinameregexp () {
296         return $GLOBALS['WikiNameRegexp'];
297     }
298     function allowedprotocols () {
299         return implode(' ', explode('|', ALLOWED_PROTOCOLS));
300     }
301     function available_plugins () {
302         $fileset = new FileSet(FindFile('lib/plugin'), '*.php');
303         $list = $fileset->getFiles();
304         natcasesort($list);
305         reset($list);
306         return sprintf(_("Total %d plugins: "), count($list))
307             . implode(', ', array_map(create_function('$f',
308                                                       'return substr($f,0,-4);'),
309                                       $list));
310     }
311     function supported_languages () {
312         $available_languages = array('en');
313         $dir_root = 'locale/';
314         if (defined('PHPWIKI_DIR'))
315             $dir_root = PHPWIKI_DIR . "/$dir_root";
316         $dir = @dir($dir_root);
317         if ($dir) {
318             while($entry = $dir->read()) {
319                 if (is_dir($dir_root . $entry)
320                     && (substr($entry, 0, 1) != '.')
321                     && $entry != 'po'
322                     && $entry != 'CVS') {
323                     array_push($available_languages, $entry);
324                 }
325             }
326             $dir->close();
327         }
328         natcasesort($available_languages);
329
330         return sprintf(_("Total of %d languages: "),
331                        count($available_languages))
332             . implode(', ', $available_languages) . ". "
333             . sprintf(_("Current language: '%s'"), $GLOBALS['LANG'])
334             . ((DEFAULT_LANGUAGE != $GLOBALS['LANG'])
335                ? ". " . sprintf(_("Default language: '%s'"), DEFAULT_LANGUAGE)
336                : '');
337     }
338
339     function supported_themes () {
340         global $Theme;
341         $available_themes = array();
342         $dir_root = 'themes/';
343         if (defined('PHPWIKI_DIR'))
344             $dir_root = PHPWIKI_DIR . "/$dir_root";
345         $dir = @dir($dir_root);
346         if ($dir) {
347             while($entry = $dir->read()) {
348                 if (is_dir($dir_root.$entry)
349                     && (substr($entry,0,1) != '.')
350                     && $entry!='CVS') {
351                     array_push($available_themes, $entry);
352                 }
353             }
354             $dir->close();
355         }
356         natcasesort($available_themes);
357         return sprintf(_("Total of %d themes: "), count($available_themes))
358             . implode(', ',$available_themes) . ". "
359             . sprintf(_("Current theme: '%s'"), $Theme->_name)
360             . ((THEME != $Theme->_name)
361                ? ". " . sprintf(_("Default theme: '%s'"), THEME)
362                : '');
363     }
364
365     function call ($arg, &$availableargs) {
366         if (!empty($availableargs[$arg]))
367             return $availableargs[$arg]();
368         elseif (method_exists($this, $arg)) // any defined SystemInfo->method()system
369             return call_user_func_array(array(&$this, $arg), '');
370         elseif (defined($arg) && $arg != 'ADMIN_PASSWD') // any defined constant
371             return constant($arg);
372         else
373             return $this->error(sprintf(_("unknown argument '%s' to SystemInfo"), $arg));
374     }
375
376     function run($dbi, $argstr, &$request, $basepage) {
377         // don't parse argstr for name=value pairs. instead we use just 'name'
378         //$args = $this->getArgs($argstr, $request);
379         $args['seperator'] = ' ';
380         $availableargs = // name => callback + 0 args
381             array ('appname' => create_function('',"return 'PhpWiki';"),
382                    'version' => create_function('',"return sprintf('%s', PHPWIKI_VERSION);"),
383                    'LANG'    => create_function('','return $GLOBALS["LANG"];'),
384                    'LC_ALL'  => create_function('','return setlocale(LC_ALL, 0);'),
385                    'current_language' => create_function('','return $GLOBALS["LANG"];'),
386                    'system_language' => create_function('','return DEFAULT_LANGUAGE;'),
387                    'current_theme' => create_function('','return $GLOBALS["Theme"]->_name;'),
388                    'system_theme'  => create_function('','return THEME;'),
389                    // more here or as method.
390                    '' => create_function('',"return 'dummy';")
391                    );
392         // split the argument string by any number of commas or space
393         // characters, which include " ", \r, \t, \n and \f
394         $allargs = preg_split("/[\s,]+/", $argstr, -1, PREG_SPLIT_NO_EMPTY);
395         if (in_array('all', $allargs) || in_array('table', $allargs)) {
396             $allargs = array('appname'          => _("Application name"),
397                              'version'          => _("PhpWiki engine version"),
398                              'database'         => _("Database"),
399                              'cachestats'       => _("Cache statistics"),
400                              'pagestats'        => _("Page statistics"),
401                              //'revisionstats'    => _("Page revision statistics"),
402                              //'linkstats'        => _("Link statistics"),
403                              'userstats'        => _("User statistics"),
404                              //'accessstats'      => _("Access statistics"),
405                              'hitstats'         => _("Hit statistics"),
406                              //'discspace'        => _("Harddisc usage"),
407                              'expireparams'     => _("Expiry parameters"),
408                              'wikinameregexp'   => _("Wikiname regexp"),
409                              'allowedprotocols' => _("Allowed protocols"),
410                              'inlineimages'     => _("Inline images"),
411                              'available_plugins'   => _("Available plugins"),
412                              'supported_languages' => _("Supported languages"),
413                              'supported_themes'    => _("Supported themes"),
414 //                           '' => _(""),
415                              '' => ""
416                              );
417             $table = HTML::table(array('border' => 1,'cellspacing' => 3,
418                                        'cellpadding' => 3));
419             foreach ($allargs as $arg => $desc) {
420                 if (!$arg)
421                     continue;
422                 if (!$desc)
423                     $desc = _($arg);
424                 $table->pushContent(HTML::tr(HTML::td(HTML::strong($desc . ':')),
425                                              HTML::td(HTML($this->call($arg, $availableargs)))));
426             }
427             return $table;
428         } else {
429             $output = '';
430             foreach ($allargs as $arg) {
431                 $o = $this->call($arg, $availableargs);
432                 if (is_object($o))
433                     return $o;
434                 else
435                     $output .= ($o . $args['seperator']);
436             }
437             // if more than one arg, remove the trailing seperator
438             if ($output) $output = substr($output, 0,
439                                           - strlen($args['seperator']));
440             return HTML($output);
441         }
442     }
443 }
444
445 /* // autolisp stdlib
446 ;;; Median of the sorted list of numbers. 50% is above and 50% below
447 ;;; "center of a distribution"
448 ;;; Ex: (std-median (std-make-list 100 std-%random)) => 0.5 +- epsilon
449 ;;;     (std-median (std-make-list 100 (lambda () (std-random 10))))
450 ;;;       => 4.0-5.0 [0..9]
451 ;;;     (std-median (std-make-list 99  (lambda () (std-random 10))))
452 ;;;       => 4-5
453 ;;;     (std-median '(0 0 2 4 12))      => 2
454 ;;;     (std-median '(0 0 4 12))        => 2.0
455 (defun STD-MEDIAN (numlst / l)
456   (setq numlst (std-sort numlst '<))            ; don't remove duplicates
457   (if (= 0 (rem (setq l (length numlst)) 2))    ; if even length
458     (* 0.5 (+ (nth (/ l 2) numlst)              ; force float!
459               (nth (1- (/ l 2)) numlst)))       ; fixed by Serge Pashkov
460     (nth (/ l 2) numlst)))
461
462 */
463 function median($hits) {
464     sort($hits);
465     reset($hits);
466     $n = count($hits);
467     $median = (int) $n / 2;
468     if (! ($n % 2)) // proper rounding on even length
469         return ($hits[$median] + $hits[$median-1]) * 0.5;
470     else
471         return $hits[$median];
472 }
473
474 function rsum($a, $b) {
475     $a += $b;
476     return $a;
477 }
478 function mean(&$hits, $total = false) {
479     $n = count($hits);
480     if (!$total)
481         $total = array_reduce($hits, 'rsum');
482     return (float) $total / ($n * 1.0);
483 }
484 function gensym($prefix = "_gensym") {
485     $i = 0;
486     while (isset($GLOBALS[$prefix . $i]))
487         $i++;
488     return $prefix . $i;
489 }
490
491 /* // autolisp stdlib
492 (defun STD-STANDARD-DEVIATION (numlst / n _dev_m r)
493   (setq n      (length numlst)
494         _dev_m (std-mean numlst)
495         r      (mapcar (function (lambda (x) (std-sqr (- x _dev_m)))) numlst))
496   (sqrt (* (std-mean r) (/ n (float (- n 1))))))
497 */
498 /*
499 function stddev(&$hits, $total=false) {
500     $n = count($hits);
501     if (!$total) $total = array_reduce($hits, 'rsum');
502     $mean = gensym("_mean");
503     $GLOBALS[$mean] = $total / $n;
504     $cb = "global ${$mean}; return (\$i-${$mean})*(\$i-${$mean});";
505     $r = array_map(create_function('$i',"global ${$mean}; return (\$i-${$mean})*(\$i-${$mean});"),$hits);
506     unset($GLOBALS[$mean]);
507     return (float) sqrt(mean($r,$total) * ($n / (float)($n -1)));
508 }
509 */
510 function stddev(&$hits, $total = false) {
511     $n = count($hits);
512     if (!$total)
513         $total = array_reduce($hits, 'rsum');
514     $GLOBALS['mean'] = $total / $n;
515     $r = array_map(create_function('$i', 'global $mean; return ($i-$mean)*($i-$mean);'),
516                    $hits);
517     unset($GLOBALS['mean']);
518     return (float)sqrt(mean($r, $total) * ($n / (float)($n -1)));
519 }
520
521 // $Log: not supported by cvs2svn $
522 // Revision 1.13  2004/04/18 01:11:52  rurban
523 // more numeric pagename fixes.
524 // fixed action=upload with merge conflict warnings.
525 // charset changed from constant to global (dynamic utf-8 switching)
526 //
527 // Revision 1.12  2004/03/14 16:26:21  rurban
528 // copyright line
529 //
530 // Revision 1.11  2004/03/13 19:24:21  rurban
531 // fixed supported_languages() and supported_themes()
532 //
533 // Revision 1.10  2004/03/08 18:17:10  rurban
534 // added more WikiGroup::getMembersOf methods, esp. for special groups
535 // fixed $LDAP_SET_OPTIONS
536 // fixed _AuthInfo group methods
537 //
538 // Revision 1.9  2004/02/17 12:11:36  rurban
539 // added missing 4th basepage arg at plugin->run() to almost all plugins. This caused no harm so far, because it was silently dropped on normal usage. However on plugin internal ->run invocations it failed. (InterWikiSearch, IncludeSiteMap, ...)
540 //
541 // Revision 1.8  2003/02/24 01:36:26  dairiki
542 // Don't use PHPWIKI_DIR unless it's defined.
543 // (Also typo/bugfix in SystemInfo plugin.)
544 //
545 // Revision 1.7  2003/02/22 20:49:56  dairiki
546 // Fixes for "Call-time pass by reference has been deprecated" errors.
547 //
548 // Revision 1.6  2003/02/21 23:01:11  dairiki
549 // Fixes to support new $basepage argument of WikiPlugin::run().
550 //
551 // Revision 1.5  2003/01/18 22:08:01  carstenklapp
552 // Code cleanup:
553 // Reformatting & tabs to spaces;
554 // Added copyleft, getVersion, getDescription, rcs_id.
555 //
556
557 // Local Variables:
558 // mode: php
559 // tab-width: 8
560 // c-basic-offset: 4
561 // c-hanging-comment-ender-p: nil
562 // indent-tabs-mode: nil
563 // End:
564 ?>