1<?php 2/** 3 * statistics plugin 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <gohr@splitbrain.org> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12/** 13 * All DokuWiki plugins to extend the admin function 14 * need to inherit from this class 15 */ 16class admin_plugin_statistics extends DokuWiki_Admin_Plugin { 17 /** @var string the currently selected page */ 18 protected $opt = ''; 19 20 /** @var string from date in YYYY-MM-DD */ 21 protected $from = ''; 22 /** @var string to date in YYYY-MM-DD */ 23 protected $to = ''; 24 /** @var int Offset to use when displaying paged data */ 25 protected $start = 0; 26 27 /** @var string MySQL timelimit statement */ 28 protected $tlimit = ''; 29 30 /** @var helper_plugin_statistics */ 31 protected $hlp; 32 33 /** 34 * Available statistic pages 35 */ 36 protected $pages = array( 37 'dashboard', 'page', 'edits', 'images', 'downloads', 38 'history', 'referer', 'newreferer', 39 'outlinks', 'searchengines', 'searchphrases', 40 'searchwords', 'internalsearchphrases', 41 'internalsearchwords', 'browsers', 'os', 42 'countries', 'resolution', 'viewport', 43 'seenusers' 44 ); 45 46 /** 47 * Initialize the helper 48 */ 49 public function __construct() { 50 $this->hlp = plugin_load('helper', 'statistics'); 51 } 52 53 /** 54 * Access for managers allowed 55 */ 56 public function forAdminOnly() { 57 return false; 58 } 59 60 /** 61 * return sort order for position in admin menu 62 */ 63 public function getMenuSort() { 64 return 350; 65 } 66 67 /** 68 * handle user request 69 */ 70 public function handle() { 71 $this->opt = preg_replace('/[^a-z]+/', '', $_REQUEST['opt']); 72 if(!in_array($this->opt, $this->pages)) $this->opt = 'dashboard'; 73 74 $this->start = (int) $_REQUEST['s']; 75 $this->setTimeframe($_REQUEST['f'], $_REQUEST['t']); 76 } 77 78 /** 79 * set limit clause 80 */ 81 public function setTimeframe($from, $to) { 82 $this->tlimit = $this->hlp->Query()->mktlimit($from, $to); 83 $this->from = $from; 84 $this->to = $to; 85 } 86 87 /** 88 * Output the Statistics 89 */ 90 function html() { 91 echo '<div id="plugin__statistics">'; 92 echo '<h1>' . $this->getLang('menu') . '</h1>'; 93 $this->html_timeselect(); 94 tpl_flush(); 95 96 $method = 'html_' . $this->opt; 97 if(method_exists($this, $method)) { 98 echo '<div class="plg_stats_' . $this->opt . '">'; 99 echo '<h2>' . $this->getLang($this->opt) . '</h2>'; 100 $this->$method(); 101 echo '</div>'; 102 } 103 echo '</div>'; 104 } 105 106 /** 107 * Return the TOC 108 * 109 * @return array 110 */ 111 function getTOC() { 112 $toc = array(); 113 foreach($this->pages as $page) { 114 $toc[] = array( 115 'link' => '?do=admin&page=statistics&opt=' . $page . '&f=' . $this->from . '&t=' . $this->to, 116 'title' => $this->getLang($page), 117 'level' => 1, 118 'type' => 'ul' 119 ); 120 } 121 return $toc; 122 } 123 124 function html_graph($name, $width, $height) { 125 $url = DOKU_BASE . 'lib/plugins/statistics/img.php?img=' . $name . 126 '&f=' . $this->from . '&t=' . $this->to; 127 echo '<img src="' . $url . '" class="graph" width="' . $width . '" height="' . $height . '"/>'; 128 } 129 130 /** 131 * Outputs pagination links 132 * 133 * @param int $limit 134 * @param int $next 135 */ 136 function html_pager($limit, $next) { 137 echo '<div class="plg_stats_pager">'; 138 139 if($this->start > 0) { 140 $go = max($this->start - $limit, 0); 141 echo '<a href="?do=admin&page=statistics&opt=' . $this->opt . '&f=' . $this->from . '&t=' . $this->to . '&s=' . $go . '" class="prev button">' . $this->getLang('prev') . '</a>'; 142 } 143 144 if($next) { 145 $go = $this->start + $limit; 146 echo '<a href="?do=admin&page=statistics&opt=' . $this->opt . '&f=' . $this->from . '&t=' . $this->to . '&s=' . $go . '" class="next button">' . $this->getLang('next') . '</a>'; 147 } 148 echo '</div>'; 149 } 150 151 /** 152 * Print the time selection menu 153 */ 154 function html_timeselect() { 155 $today = date('Y-m-d'); 156 $last1 = date('Y-m-d', time() - (60 * 60 * 24)); 157 $last7 = date('Y-m-d', time() - (60 * 60 * 24 * 7)); 158 $last30 = date('Y-m-d', time() - (60 * 60 * 24 * 30)); 159 160 echo '<div class="plg_stats_timeselect">'; 161 echo '<span>' . $this->getLang('time_select') . '</span> '; 162 163 echo '<form action="" method="get">'; 164 echo '<input type="hidden" name="do" value="admin" />'; 165 echo '<input type="hidden" name="page" value="statistics" />'; 166 echo '<input type="hidden" name="opt" value="' . $this->opt . '" />'; 167 echo '<input type="text" name="f" value="' . $this->from . '" class="edit" />'; 168 echo '<input type="text" name="t" value="' . $this->to . '" class="edit" />'; 169 echo '<input type="submit" value="go" class="button" />'; 170 echo '</form>'; 171 172 echo '<ul>'; 173 foreach(array('today', 'last1', 'last7', 'last30') as $time) { 174 echo '<li>'; 175 echo '<a href="?do=admin&page=statistics&opt=' . $this->opt . '&f=' . $$time . '&t=' . $today . '">'; 176 echo $this->getLang('time_' . $time); 177 echo '</a>'; 178 echo '</li>'; 179 } 180 echo '</ul>'; 181 182 echo '</div>'; 183 } 184 185 /** 186 * Print an introductionary screen 187 */ 188 function html_dashboard() { 189 echo '<p>' . $this->getLang('intro_dashboard') . '</p>'; 190 191 // general info 192 echo '<div class="plg_stats_top">'; 193 $result = $this->hlp->Query()->aggregate($this->tlimit); 194 195 echo '<ul class="left">'; 196 foreach(array('pageviews', 'sessions', 'visitors', 'users', 'logins', 'current') as $name) { 197 echo '<li><div class="li">' . sprintf($this->getLang('dash_' . $name), $result[$name]) . '</div></li>'; 198 } 199 echo '</ul>'; 200 201 echo '<ul class="left">'; 202 foreach(array('bouncerate', 'timespent', 'avgpages', 'newvisitors', 'registrations') as $name) { 203 echo '<li><div class="li">' . sprintf($this->getLang('dash_' . $name), $result[$name]) . '</div></li>'; 204 } 205 echo '</ul>'; 206 207 $this->html_graph('dashboardviews', 700, 280); 208 $this->html_graph('dashboardwiki', 700, 280); 209 echo '</div>'; 210 211 // top pages today 212 echo '<div>'; 213 echo '<h2>' . $this->getLang('dash_mostpopular') . '</h2>'; 214 $result = $this->hlp->Query()->pages($this->tlimit, $this->start, 15); 215 $this->html_resulttable($result); 216 echo '<a href="?do=admin&page=statistics&opt=page&f=' . $this->from . '&t=' . $this->to . '" class="more button">' . $this->getLang('more') . '</a>'; 217 echo '</div>'; 218 219 // top referer today 220 echo '<div>'; 221 echo '<h2>' . $this->getLang('dash_newincoming') . '</h2>'; 222 $result = $this->hlp->Query()->newreferer($this->tlimit, $this->start, 15); 223 $this->html_resulttable($result); 224 echo '<a href="?do=admin&page=statistics&opt=newreferer&f=' . $this->from . '&t=' . $this->to . '" class="more button">' . $this->getLang('more') . '</a>'; 225 echo '</div>'; 226 227 // top searches today 228 echo '<div>'; 229 echo '<h2>' . $this->getLang('dash_topsearch') . '</h2>'; 230 $result = $this->hlp->Query()->searchphrases(true, $this->tlimit, $this->start, 15); 231 $this->html_resulttable($result); 232 echo '<a href="?do=admin&page=statistics&opt=searchphrases&f=' . $this->from . '&t=' . $this->to . '" class="more button">' . $this->getLang('more') . '</a>'; 233 echo '</div>'; 234 } 235 236 function html_history() { 237 echo '<p>' . $this->getLang('intro_history') . '</p>'; 238 $this->html_graph('history', 600, 200); 239 #$result = $this->hlp->Query()->countries($this->tlimit, $this->start, 150); 240 #$this->html_resulttable($result, '', 150); 241 } 242 243 function html_countries() { 244 echo '<p>' . $this->getLang('intro_countries') . '</p>'; 245 $this->html_graph('countries', 400, 200); 246 $result = $this->hlp->Query()->countries($this->tlimit, $this->start, 150); 247 $this->html_resulttable($result, '', 150); 248 } 249 250 function html_page() { 251 echo '<p>' . $this->getLang('intro_page') . '</p>'; 252 $result = $this->hlp->Query()->pages($this->tlimit, $this->start, 150); 253 $this->html_resulttable($result, '', 150); 254 } 255 256 function html_edits() { 257 echo '<p>' . $this->getLang('intro_edits') . '</p>'; 258 $result = $this->hlp->Query()->edits($this->tlimit, $this->start, 150); 259 $this->html_resulttable($result, '', 150); 260 } 261 262 function html_images() { 263 echo '<p>' . $this->getLang('intro_images') . '</p>'; 264 $result = $this->hlp->Query()->images($this->tlimit, $this->start, 150); 265 $this->html_resulttable($result, '', 150); 266 } 267 268 function html_downloads() { 269 echo '<p>' . $this->getLang('intro_downloads') . '</p>'; 270 $result = $this->hlp->Query()->downloads($this->tlimit, $this->start, 150); 271 $this->html_resulttable($result, '', 150); 272 } 273 274 function html_browsers() { 275 echo '<p>' . $this->getLang('intro_browsers') . '</p>'; 276 $this->html_graph('browsers', 400, 200); 277 $result = $this->hlp->Query()->browsers($this->tlimit, $this->start, 150, true); 278 $this->html_resulttable($result, '', 150); 279 } 280 281 function html_os() { 282 echo '<p>' . $this->getLang('intro_os') . '</p>'; 283 $this->html_graph('os', 400, 200); 284 $result = $this->hlp->Query()->os($this->tlimit, $this->start, 150, true); 285 $this->html_resulttable($result, '', 150); 286 } 287 288 function html_referer() { 289 $result = $this->hlp->Query()->aggregate($this->tlimit); 290 291 $all = $result['search'] + $result['external'] + $result['direct']; 292 293 if($all) { 294 printf( 295 '<p>' . $this->getLang('intro_referer') . '</p>', 296 $all, $result['direct'], (100 * $result['direct'] / $all), 297 $result['search'], (100 * $result['search'] / $all), $result['external'], 298 (100 * $result['external'] / $all) 299 ); 300 } 301 302 $result = $this->hlp->Query()->referer($this->tlimit, $this->start, 150); 303 $this->html_resulttable($result, '', 150); 304 } 305 306 function html_newreferer() { 307 echo '<p>' . $this->getLang('intro_newreferer') . '</p>'; 308 309 $result = $this->hlp->Query()->newreferer($this->tlimit, $this->start, 150); 310 $this->html_resulttable($result, '', 150); 311 } 312 313 function html_outlinks() { 314 echo '<p>' . $this->getLang('intro_outlinks') . '</p>'; 315 $result = $this->hlp->Query()->outlinks($this->tlimit, $this->start, 150); 316 $this->html_resulttable($result, '', 150); 317 } 318 319 function html_searchphrases() { 320 echo '<p>' . $this->getLang('intro_searchphrases') . '</p>'; 321 $result = $this->hlp->Query()->searchphrases(true, $this->tlimit, $this->start, 150); 322 $this->html_resulttable($result, '', 150); 323 } 324 325 function html_searchwords() { 326 echo '<p>' . $this->getLang('intro_searchwords') . '</p>'; 327 $result = $this->hlp->Query()->searchwords(true, $this->tlimit, $this->start, 150); 328 $this->html_resulttable($result, '', 150); 329 } 330 331 function html_internalsearchphrases() { 332 echo '<p>' . $this->getLang('intro_internalsearchphrases') . '</p>'; 333 $result = $this->hlp->Query()->searchphrases(false, $this->tlimit, $this->start, 150); 334 $this->html_resulttable($result, '', 150); 335 } 336 337 function html_internalsearchwords() { 338 echo '<p>' . $this->getLang('intro_internalsearchwords') . '</p>'; 339 $result = $this->hlp->Query()->searchwords(false, $this->tlimit, $this->start, 150); 340 $this->html_resulttable($result, '', 150); 341 } 342 343 function html_searchengines() { 344 echo '<p>' . $this->getLang('intro_searchengines') . '</p>'; 345 $this->html_graph('searchengines', 400, 200); 346 $result = $this->hlp->Query()->searchengines($this->tlimit, $this->start, 150); 347 $this->html_resulttable($result, '', 150); 348 } 349 350 function html_resolution() { 351 echo '<p>' . $this->getLang('intro_resolution') . '</p>'; 352 $this->html_graph('resolution', 650, 490); 353 $result = $this->hlp->Query()->resolution($this->tlimit, $this->start, 150); 354 $this->html_resulttable($result, '', 150); 355 } 356 357 function html_viewport() { 358 echo '<p>' . $this->getLang('intro_viewport') . '</p>'; 359 $this->html_graph('viewport', 650, 490); 360 $result = $this->hlp->Query()->viewport($this->tlimit, $this->start, 150); 361 $this->html_resulttable($result, '', 150); 362 } 363 364 function html_seenusers() { 365 echo '<p>' . $this->getLang('intro_seenusers') . '</p>'; 366 $result = $this->hlp->Query()->seenusers($this->tlimit, $this->start, 150); 367 $this->html_resulttable($result, '', 150); 368 } 369 370 /** 371 * Display a result in a HTML table 372 */ 373 function html_resulttable($result, $header = '', $pager = 0) { 374 echo '<table>'; 375 if(is_array($header)) { 376 echo '<tr>'; 377 foreach($header as $h) { 378 echo '<th>' . hsc($h) . '</th>'; 379 } 380 echo '</tr>'; 381 } 382 383 $count = 0; 384 if(is_array($result)) foreach($result as $row) { 385 echo '<tr>'; 386 foreach($row as $k => $v) { 387 if($k == 'res_x') continue; 388 if($k == 'res_y') continue; 389 390 echo '<td class="plg_stats_X' . $k . '">'; 391 if($k == 'page') { 392 echo '<a href="' . wl($v) . '" class="wikilink1">'; 393 echo hsc($v); 394 echo '</a>'; 395 } elseif($k == 'media') { 396 echo '<a href="' . ml($v) . '" class="wikilink1">'; 397 echo hsc($v); 398 echo '</a>'; 399 } elseif($k == 'filesize') { 400 echo filesize_h($v); 401 } elseif($k == 'url') { 402 $url = hsc($v); 403 $url = preg_replace('/^https?:\/\/(www\.)?/', '', $url); 404 if(strlen($url) > 45) { 405 $url = substr($url, 0, 30) . ' … ' . substr($url, -15); 406 } 407 echo '<a href="' . $v . '" class="urlextern">'; 408 echo $url; 409 echo '</a>'; 410 } elseif($k == 'ilookup') { 411 echo '<a href="' . wl('', array('id' => $v, 'do' => 'search')) . '">Search</a>'; 412 } elseif($k == 'lookup') { 413 echo '<a href="http://www.google.com/search?q=' . rawurlencode($v) . '">'; 414 echo '<img src="' . DOKU_BASE . 'lib/plugins/statistics/ico/search/google.png" alt="Google" border="0" />'; 415 echo '</a> '; 416 417 echo '<a href="http://search.yahoo.com/search?p=' . rawurlencode($v) . '">'; 418 echo '<img src="' . DOKU_BASE . 'lib/plugins/statistics/ico/search/yahoo.png" alt="Yahoo!" border="0" />'; 419 echo '</a> '; 420 421 echo '<a href="http://www.bing.com/search?q=' . rawurlencode($v) . '">'; 422 echo '<img src="' . DOKU_BASE . 'lib/plugins/statistics/ico/search/bing.png" alt="Bing" border="0" />'; 423 echo '</a> '; 424 425 } elseif($k == 'engine') { 426 include_once(dirname(__FILE__) . '/inc/searchengines.php'); 427 if(isset($SEARCHENGINEINFO[$v])) { 428 echo '<a href="' . $SEARCHENGINEINFO[$v][1] . '">' . $SEARCHENGINEINFO[$v][0] . '</a>'; 429 } else { 430 echo hsc(ucwords($v)); 431 } 432 } elseif($k == 'eflag') { 433 $this->html_icon('search', $v); 434 } elseif($k == 'bflag') { 435 $this->html_icon('browser', $v); 436 } elseif($k == 'osflag') { 437 $this->html_icon('os', $v); 438 } elseif($k == 'cflag') { 439 $this->html_icon('flags', $v); 440 } elseif($k == 'html') { 441 echo $v; 442 } else { 443 echo hsc($v); 444 } 445 echo '</td>'; 446 } 447 echo '</tr>'; 448 449 if($pager && ($count == $pager)) break; 450 $count++; 451 } 452 echo '</table>'; 453 454 if($pager) $this->html_pager($pager, count($result) > $pager); 455 } 456 457 function html_icon($type, $value) { 458 $value = strtolower(preg_replace('/[^\w]+/', '', $value)); 459 $value = str_replace(' ', '_', $value); 460 $file = 'lib/plugins/statistics/ico/' . $type . '/' . $value . '.png'; 461 if($type == 'flags') { 462 $w = 18; 463 $h = 12; 464 } else { 465 $w = 16; 466 $h = 16; 467 } 468 if(file_exists(DOKU_INC . $file)) { 469 echo '<img src="' . DOKU_BASE . $file . '" alt="' . hsc($value) . '" width="' . $w . '" height="' . $h . '" />'; 470 } 471 } 472} 473