2 rcs_id('$Id: SystemInfo.php,v 1.17 2004-05-08 14:06:13 rurban Exp $');
4 Copyright (C) 1999, 2000, 2001, 2002 $ThePhpWikiProgrammingTeam
6 This file is part of PhpWiki.
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.
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.
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
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 ?>
30 * Provide access to phpwiki's lower level system information.
32 * version, charset, pagestats, SERVER_NAME, database, discspace,
33 * cachestats, userstats, linkstats, accessstats, hitstats,
34 * revisionstats, interwikilinks, imageextensions, wikiwordregexp,
35 * availableplugins, downloadurl or any other predefined CONSTANT
37 * In spirit to http://www.ecyrd.com/JSPWiki/SystemInfo.jsp
39 * Todo: Some calculations are heavy (~5-8 secs), so we should cache
40 * the result. In the page or with WikiPluginCached?
42 //require_once "lib/WikiPluginCached.php";
44 class WikiPlugin_SystemInfo
45 //extends WikiPluginCached
48 function getPluginType() {
49 return PLUGIN_CACHED_HTML;
52 return _("SystemInfo");
55 function getDescription() {
56 return _("Provides access to PhpWiki's lower level system information.");
59 function getVersion() {
60 return preg_replace("/[Revision: $]/", '',
61 "\$Revision: 1.17 $");
64 function getExpire($dbi, $argarray, $request) {
65 return '+1800'; // 30 minutes
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);
74 function getDefaultArguments() {
76 'seperator' => ' ', // on multiple args
82 global $DBParams, $request;
83 $s = _("db type:") . " {$DBParams['dbtype']}, ";
84 switch ($DBParams['dbtype']) {
87 $dsn = $DBParams['dsn'];
88 $s .= _("db backend:") . " ";
89 $s .= ($DBParams['dbtype'] == 'SQL') ? 'PearDB' : 'ADODB';
90 if (preg_match('/^(\w+):/', $dsn, $m)) {
96 $s .= _("dba handler:") . " {$DBParams['dba_handler']}, ";
99 // $s .= "cvs stuff: , ";
102 // $s .= "flatfile stuff: , ";
105 // hack: suppress error when using sql, so no timeout
106 @$s .= _("timeout:") . " {$DBParams['timeout']}";
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: ?";
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']);
139 function pagestats() {
143 $dbi = $request->getDbh();
144 $include_empty = true;
145 $iter = $dbi->getAllPages($include_empty);
146 while ($page = $iter->next())
148 $s = sprintf(_("%d pages"), $e);
149 $include_empty = false;
150 $iter = $dbi->getAllPages($include_empty);
151 while ($page = $iter->next())
153 $s .= ", " . sprintf(_("%d not-empty pages"), $a);
155 // $s .= ", " . sprintf(_("earliest page from %s"), $earliestdate);
156 // $s .= ", " . sprintf(_("latest page from %s"), $latestdate);
157 // $s .= ", " . sprintf(_("latest pagerevision from %s"), $latestrevdate);
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() {
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() {
174 $dbi = $request->getDbh();
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.
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?
188 //only from logging info possible. = hitstats per time.
189 // total hits per day/month/year
191 // TODO: see WhoIsOnline hit stats
192 function accessstats() {
196 // only absolute numbers, not for any time interval. see accessstats
197 // some useful number derived from the curve of the hit stats.
198 // total, max, mean, median, stddev;
199 // %d pages less than 3 hits (<10%) <10% percent of the leastpopular
200 // %d pages more than 100 hits (>90%) >90% percent of the mostpopular
201 function hitstats() {
203 $dbi = $request->getDbh();
207 $page_iter = $dbi->getAllPages(true);
208 while ($page = $page_iter->next()) {
209 if (($current = $page->getCurrentRevision())
210 && (! $current->hasDefaultContents())) {
211 $h = $page->get('hits');
214 $max = max($h, $max);
220 $median_i = (int) $n / 2;
222 $median = $hits[$median_i];
224 $median = $hits[$median_i];
225 $stddev = stddev($hits, $total);
227 $s = sprintf(_("total hits: %d"), $total);
228 $s .= ", " . sprintf(_("max: %d"), $max);
229 $s .= ", " . sprintf(_("mean: %2.3f"), $total / $n);
230 $s .= ", " . sprintf(_("median: %d"), $median);
231 $s .= ", " . sprintf(_("stddev: %2.3f"), $stddev);
233 $mintreshold = $max * $percentage / 100.0; // lower than 10% of the hits
235 $nmin = $hits[0] < $mintreshold ? 1 : 0;
236 while (next($hits) < $mintreshold)
238 $maxtreshold = $max - $mintreshold; // more than 90% of the hits
241 while (prev($hits) > $maxtreshold)
243 $s .= "; " . sprintf(_("%d pages with less than %d hits (<%d%%)."),
244 $nmin, $mintreshold, $percentage);
245 $s .= " " . sprintf(_("%d page(s) with more than %d hits (>%d%%)."),
246 $nmax, $maxtreshold, 100 - $percentage);
249 function revisionstats() {
251 $dbi = $request->getDbh();
255 $page_iter = $dbi->getAllPages(true);
256 while ($page = $page_iter->next()) {
257 if ($current = $page->getCurrentRevision()
258 && (! $current->hasDefaultContents())) {
259 //$ma = $page->get('major');
260 //$mi = $page->get('minor');
266 // Size of databases/files/cvs are possible plus the known size of the app.
267 // Todo: cache this costly operation!
268 function discspace() {
270 $dir = defined('PHPWIKI_DIR') ? PHPWIKI_DIR : '.';
271 $appsize = `du -s $dir | cut -f1`;
273 if (in_array($DBParams['dbtype'], array('SQL', 'ADODB'))) {
275 } elseif ($DBParams['dbtype'] == 'dba') {
277 $dbdir = $DBParams['directory'];
278 if ($DBParams['dba_handler'] == 'db3')
279 $pagesize = filesize($DBParams['directory']
280 . "/wiki_pagedb.db3") / 1024;
281 // if issubdirof($dbdir, $dir) $appsize -= $pagesize;
282 } else { // flatfile, cvs
283 $dbdir = $DBParams['directory'];
284 $pagesize = `du -s $dbdir`;
285 // if issubdirof($dbdir, $dir) $appsize -= $pagesize;
287 $s = sprintf(_("Application size: %d Kb"), $appsize);
289 $s .= ", " . sprintf(_("Pagedata size: %d Kb", $pagesize));
293 function inlineimages () {
294 return implode(' ', explode('|', INLINE_IMAGES));
296 function wikinameregexp () {
297 return $GLOBALS['WikiNameRegexp'];
299 function allowedprotocols () {
300 return implode(' ', explode('|', ALLOWED_PROTOCOLS));
302 function available_plugins () {
303 $fileset = new FileSet(FindFile('lib/plugin'), '*.php');
304 $list = $fileset->getFiles();
307 return sprintf(_("Total %d plugins: "), count($list))
308 . implode(', ', array_map(create_function('$f',
309 'return substr($f,0,-4);'),
312 function supported_languages () {
313 $available_languages = listAvailableLanguages();
314 natcasesort($available_languages);
316 return sprintf(_("Total of %d languages: "),
317 count($available_languages))
318 . implode(', ', $available_languages) . ". "
319 . sprintf(_("Current language: '%s'"), $GLOBALS['LANG'])
320 . ((DEFAULT_LANGUAGE != $GLOBALS['LANG'])
321 ? ". " . sprintf(_("Default language: '%s'"), DEFAULT_LANGUAGE)
325 function supported_themes () {
327 $available_themes = listAvailableThemes();
328 natcasesort($available_themes);
329 return sprintf(_("Total of %d themes: "), count($available_themes))
330 . implode(', ',$available_themes) . ". "
331 . sprintf(_("Current theme: '%s'"), $Theme->_name)
332 . ((THEME != $Theme->_name)
333 ? ". " . sprintf(_("Default theme: '%s'"), THEME)
337 function call ($arg, &$availableargs) {
338 if (!empty($availableargs[$arg]))
339 return $availableargs[$arg]();
340 elseif (method_exists($this, $arg)) // any defined SystemInfo->method()
341 return call_user_func_array(array(&$this, $arg), '');
342 elseif (defined($arg) && $arg != 'ADMIN_PASSWD') // any defined constant
343 return constant($arg);
345 return $this->error(sprintf(_("unknown argument '%s' to SystemInfo"), $arg));
348 function run($dbi, $argstr, &$request, $basepage) {
349 // don't parse argstr for name=value pairs. instead we use just 'name'
350 //$args = $this->getArgs($argstr, $request);
351 $args['seperator'] = ' ';
352 $availableargs = // name => callback + 0 args
353 array ('appname' => create_function('',"return 'PhpWiki';"),
354 'version' => create_function('',"return sprintf('%s', PHPWIKI_VERSION);"),
355 'LANG' => create_function('','return $GLOBALS["LANG"];'),
356 'LC_ALL' => create_function('','return setlocale(LC_ALL, 0);'),
357 'current_language' => create_function('','return $GLOBALS["LANG"];'),
358 'system_language' => create_function('','return DEFAULT_LANGUAGE;'),
359 'current_theme' => create_function('','return $GLOBALS["Theme"]->_name;'),
360 'system_theme' => create_function('','return THEME;'),
361 // more here or as method.
362 '' => create_function('',"return 'dummy';")
364 // split the argument string by any number of commas or space
365 // characters, which include " ", \r, \t, \n and \f
366 $allargs = preg_split("/[\s,]+/", $argstr, -1, PREG_SPLIT_NO_EMPTY);
367 if (in_array('all', $allargs) || in_array('table', $allargs)) {
368 $allargs = array('appname' => _("Application name"),
369 'version' => _("PhpWiki engine version"),
370 'database' => _("Database"),
371 'cachestats' => _("Cache statistics"),
372 'pagestats' => _("Page statistics"),
373 //'revisionstats' => _("Page revision statistics"),
374 //'linkstats' => _("Link statistics"),
375 'userstats' => _("User statistics"),
376 //'accessstats' => _("Access statistics"),
377 'hitstats' => _("Hit statistics"),
378 //'discspace' => _("Harddisc usage"),
379 'expireparams' => _("Expiry parameters"),
380 'wikinameregexp' => _("Wikiname regexp"),
381 'allowedprotocols' => _("Allowed protocols"),
382 'inlineimages' => _("Inline images"),
383 'available_plugins' => _("Available plugins"),
384 'supported_languages' => _("Supported languages"),
385 'supported_themes' => _("Supported themes"),
389 $table = HTML::table(array('border' => 1,'cellspacing' => 3,
390 'cellpadding' => 3));
391 foreach ($allargs as $arg => $desc) {
396 $table->pushContent(HTML::tr(HTML::td(HTML::strong($desc . ':')),
397 HTML::td(HTML($this->call($arg, $availableargs)))));
402 foreach ($allargs as $arg) {
403 $o = $this->call($arg, $availableargs);
407 $output .= ($o . $args['seperator']);
409 // if more than one arg, remove the trailing seperator
410 if ($output) $output = substr($output, 0,
411 - strlen($args['seperator']));
412 return HTML($output);
417 /* // autolisp stdlib
418 ;;; Median of the sorted list of numbers. 50% is above and 50% below
419 ;;; "center of a distribution"
420 ;;; Ex: (std-median (std-make-list 100 std-%random)) => 0.5 +- epsilon
421 ;;; (std-median (std-make-list 100 (lambda () (std-random 10))))
422 ;;; => 4.0-5.0 [0..9]
423 ;;; (std-median (std-make-list 99 (lambda () (std-random 10))))
425 ;;; (std-median '(0 0 2 4 12)) => 2
426 ;;; (std-median '(0 0 4 12)) => 2.0
427 (defun STD-MEDIAN (numlst / l)
428 (setq numlst (std-sort numlst '<)) ; don't remove duplicates
429 (if (= 0 (rem (setq l (length numlst)) 2)) ; if even length
430 (* 0.5 (+ (nth (/ l 2) numlst) ; force float!
431 (nth (1- (/ l 2)) numlst))) ; fixed by Serge Pashkov
432 (nth (/ l 2) numlst)))
435 function median($hits) {
439 $median = (int) $n / 2;
440 if (! ($n % 2)) // proper rounding on even length
441 return ($hits[$median] + $hits[$median-1]) * 0.5;
443 return $hits[$median];
446 function rsum($a, $b) {
450 function mean(&$hits, $total = false) {
453 $total = array_reduce($hits, 'rsum');
454 return (float) $total / ($n * 1.0);
456 function gensym($prefix = "_gensym") {
458 while (isset($GLOBALS[$prefix . $i]))
463 /* // autolisp stdlib
464 (defun STD-STANDARD-DEVIATION (numlst / n _dev_m r)
465 (setq n (length numlst)
466 _dev_m (std-mean numlst)
467 r (mapcar (function (lambda (x) (std-sqr (- x _dev_m)))) numlst))
468 (sqrt (* (std-mean r) (/ n (float (- n 1))))))
470 function stddev(&$hits, $total = false) {
472 if (!$total) $total = array_reduce($hits, 'rsum');
473 $GLOBALS['mean'] = $total / $n;
474 $r = array_map(create_function('$i', 'global $mean; return ($i-$mean)*($i-$mean);'),
476 unset($GLOBALS['mean']);
477 return (float)sqrt(mean($r, $total) * ($n / (float)($n -1)));
480 // $Log: not supported by cvs2svn $
481 // Revision 1.16 2004/05/06 20:30:47 rurban
482 // revert and removed some comments
484 // Revision 1.15 2004/05/03 11:40:42 rurban
485 // put listAvailableLanguages() and listAvailableThemes() from SystemInfo and
486 // UserPreferences into Themes.php
488 // Revision 1.14 2004/04/19 23:13:04 zorloc
489 // Connect the rest of PhpWiki to the IniConfig system. Also the keyword regular expression is not a config setting
491 // Revision 1.13 2004/04/18 01:11:52 rurban
492 // more numeric pagename fixes.
493 // fixed action=upload with merge conflict warnings.
494 // charset changed from constant to global (dynamic utf-8 switching)
496 // Revision 1.12 2004/03/14 16:26:21 rurban
499 // Revision 1.11 2004/03/13 19:24:21 rurban
500 // fixed supported_languages() and supported_themes()
502 // Revision 1.10 2004/03/08 18:17:10 rurban
503 // added more WikiGroup::getMembersOf methods, esp. for special groups
504 // fixed $LDAP_SET_OPTIONS
505 // fixed _AuthInfo group methods
507 // Revision 1.9 2004/02/17 12:11:36 rurban
508 // 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, ...)
510 // Revision 1.8 2003/02/24 01:36:26 dairiki
511 // Don't use PHPWIKI_DIR unless it's defined.
512 // (Also typo/bugfix in SystemInfo plugin.)
514 // Revision 1.7 2003/02/22 20:49:56 dairiki
515 // Fixes for "Call-time pass by reference has been deprecated" errors.
517 // Revision 1.6 2003/02/21 23:01:11 dairiki
518 // Fixes to support new $basepage argument of WikiPlugin::run().
520 // Revision 1.5 2003/01/18 22:08:01 carstenklapp
522 // Reformatting & tabs to spaces;
523 // Added copyleft, getVersion, getDescription, rcs_id.
530 // c-hanging-comment-ender-p: nil
531 // indent-tabs-mode: nil