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 '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_countries() { 237 echo '<p>' . $this->getLang('intro_countries') . '</p>'; 238 $this->html_graph('countries', 400, 200); 239 $result = $this->hlp->Query()->countries($this->tlimit, $this->start, 150); 240 $this->html_resulttable($result, '', 150); 241 } 242 243 function html_page() { 244 echo '<p>' . $this->getLang('intro_page') . '</p>'; 245 $result = $this->hlp->Query()->pages($this->tlimit, $this->start, 150); 246 $this->html_resulttable($result, '', 150); 247 } 248 249 function html_edits() { 250 echo '<p>' . $this->getLang('intro_edits') . '</p>'; 251 $result = $this->hlp->Query()->edits($this->tlimit, $this->start, 150); 252 $this->html_resulttable($result, '', 150); 253 } 254 255 function html_images() { 256 echo '<p>' . $this->getLang('intro_images') . '</p>'; 257 $result = $this->hlp->Query()->images($this->tlimit, $this->start, 150); 258 $this->html_resulttable($result, '', 150); 259 } 260 261 function html_downloads() { 262 echo '<p>' . $this->getLang('intro_downloads') . '</p>'; 263 $result = $this->hlp->Query()->downloads($this->tlimit, $this->start, 150); 264 $this->html_resulttable($result, '', 150); 265 } 266 267 function html_browsers() { 268 echo '<p>' . $this->getLang('intro_browsers') . '</p>'; 269 $this->html_graph('browsers', 400, 200); 270 $result = $this->hlp->Query()->browsers($this->tlimit, $this->start, 150, true); 271 $this->html_resulttable($result, '', 150); 272 } 273 274 function html_os() { 275 echo '<p>' . $this->getLang('intro_os') . '</p>'; 276 $this->html_graph('os', 400, 200); 277 $result = $this->hlp->Query()->os($this->tlimit, $this->start, 150, true); 278 $this->html_resulttable($result, '', 150); 279 } 280 281 function html_referer() { 282 $result = $this->hlp->Query()->aggregate($this->tlimit); 283 284 $all = $result['search'] + $result['external'] + $result['direct']; 285 286 if($all) { 287 printf( 288 '<p>' . $this->getLang('intro_referer') . '</p>', 289 $all, $result['direct'], (100 * $result['direct'] / $all), 290 $result['search'], (100 * $result['search'] / $all), $result['external'], 291 (100 * $result['external'] / $all) 292 ); 293 } 294 295 $result = $this->hlp->Query()->referer($this->tlimit, $this->start, 150); 296 $this->html_resulttable($result, '', 150); 297 } 298 299 function html_newreferer() { 300 echo '<p>' . $this->getLang('intro_newreferer') . '</p>'; 301 302 $result = $this->hlp->Query()->newreferer($this->tlimit, $this->start, 150); 303 $this->html_resulttable($result, '', 150); 304 } 305 306 function html_outlinks() { 307 echo '<p>' . $this->getLang('intro_outlinks') . '</p>'; 308 $result = $this->hlp->Query()->outlinks($this->tlimit, $this->start, 150); 309 $this->html_resulttable($result, '', 150); 310 } 311 312 function html_searchphrases() { 313 echo '<p>' . $this->getLang('intro_searchphrases') . '</p>'; 314 $result = $this->hlp->Query()->searchphrases(true, $this->tlimit, $this->start, 150); 315 $this->html_resulttable($result, '', 150); 316 } 317 318 function html_searchwords() { 319 echo '<p>' . $this->getLang('intro_searchwords') . '</p>'; 320 $result = $this->hlp->Query()->searchwords(true, $this->tlimit, $this->start, 150); 321 $this->html_resulttable($result, '', 150); 322 } 323 324 function html_internalsearchphrases() { 325 echo '<p>' . $this->getLang('intro_internalsearchphrases') . '</p>'; 326 $result = $this->hlp->Query()->searchphrases(false, $this->tlimit, $this->start, 150); 327 $this->html_resulttable($result, '', 150); 328 } 329 330 function html_internalsearchwords() { 331 echo '<p>' . $this->getLang('intro_internalsearchwords') . '</p>'; 332 $result = $this->hlp->Query()->searchwords(false, $this->tlimit, $this->start, 150); 333 $this->html_resulttable($result, '', 150); 334 } 335 336 function html_searchengines() { 337 echo '<p>' . $this->getLang('intro_searchengines') . '</p>'; 338 $this->html_graph('searchengines', 400, 200); 339 $result = $this->hlp->Query()->searchengines($this->tlimit, $this->start, 150); 340 $this->html_resulttable($result, '', 150); 341 } 342 343 function html_resolution() { 344 echo '<p>' . $this->getLang('intro_resolution') . '</p>'; 345 $this->html_graph('resolution', 650, 490); 346 $result = $this->hlp->Query()->resolution($this->tlimit, $this->start, 150); 347 $this->html_resulttable($result, '', 150); 348 } 349 350 function html_viewport() { 351 echo '<p>' . $this->getLang('intro_viewport') . '</p>'; 352 $this->html_graph('viewport', 650, 490); 353 $result = $this->hlp->Query()->viewport($this->tlimit, $this->start, 150); 354 $this->html_resulttable($result, '', 150); 355 } 356 357 function html_seenusers() { 358 echo '<p>' . $this->getLang('intro_seenusers') . '</p>'; 359 $result = $this->hlp->Query()->seenusers($this->tlimit, $this->start, 150); 360 $this->html_resulttable($result, '', 150); 361 } 362 363 /** 364 * Display a result in a HTML table 365 */ 366 function html_resulttable($result, $header = '', $pager = 0) { 367 echo '<table>'; 368 if(is_array($header)) { 369 echo '<tr>'; 370 foreach($header as $h) { 371 echo '<th>' . hsc($h) . '</th>'; 372 } 373 echo '</tr>'; 374 } 375 376 $count = 0; 377 if(is_array($result)) foreach($result as $row) { 378 echo '<tr>'; 379 foreach($row as $k => $v) { 380 if($k == 'res_x') continue; 381 if($k == 'res_y') continue; 382 383 echo '<td class="plg_stats_X' . $k . '">'; 384 if($k == 'page') { 385 echo '<a href="' . wl($v) . '" class="wikilink1">'; 386 echo hsc($v); 387 echo '</a>'; 388 } elseif($k == 'media') { 389 echo '<a href="' . ml($v) . '" class="wikilink1">'; 390 echo hsc($v); 391 echo '</a>'; 392 } elseif($k == 'filesize') { 393 echo filesize_h($v); 394 } elseif($k == 'url') { 395 $url = hsc($v); 396 $url = preg_replace('/^https?:\/\/(www\.)?/', '', $url); 397 if(strlen($url) > 45) { 398 $url = substr($url, 0, 30) . ' … ' . substr($url, -15); 399 } 400 echo '<a href="' . $v . '" class="urlextern">'; 401 echo $url; 402 echo '</a>'; 403 } elseif($k == 'ilookup') { 404 echo '<a href="' . wl('', array('id' => $v, 'do' => 'search')) . '">Search</a>'; 405 } elseif($k == 'lookup') { 406 echo '<a href="http://www.google.com/search?q=' . rawurlencode($v) . '">'; 407 echo '<img src="' . DOKU_BASE . 'lib/plugins/statistics/ico/search/google.png" alt="Google" border="0" />'; 408 echo '</a> '; 409 410 echo '<a href="http://search.yahoo.com/search?p=' . rawurlencode($v) . '">'; 411 echo '<img src="' . DOKU_BASE . 'lib/plugins/statistics/ico/search/yahoo.png" alt="Yahoo!" border="0" />'; 412 echo '</a> '; 413 414 echo '<a href="http://www.bing.com/search?q=' . rawurlencode($v) . '">'; 415 echo '<img src="' . DOKU_BASE . 'lib/plugins/statistics/ico/search/bing.png" alt="Bing" border="0" />'; 416 echo '</a> '; 417 418 } elseif($k == 'engine') { 419 include_once(dirname(__FILE__) . '/inc/searchengines.php'); 420 if(isset($SEARCHENGINEINFO[$v])) { 421 echo '<a href="' . $SEARCHENGINEINFO[$v][1] . '">' . $SEARCHENGINEINFO[$v][0] . '</a>'; 422 } else { 423 echo hsc(ucwords($v)); 424 } 425 } elseif($k == 'eflag') { 426 $this->html_icon('search', $v); 427 } elseif($k == 'bflag') { 428 $this->html_icon('browser', $v); 429 } elseif($k == 'osflag') { 430 $this->html_icon('os', $v); 431 } elseif($k == 'cflag') { 432 $this->html_icon('flags', $v); 433 } elseif($k == 'html') { 434 echo $v; 435 } else { 436 echo hsc($v); 437 } 438 echo '</td>'; 439 } 440 echo '</tr>'; 441 442 if($pager && ($count == $pager)) break; 443 $count++; 444 } 445 echo '</table>'; 446 447 if($pager) $this->html_pager($pager, count($result) > $pager); 448 } 449 450 function html_icon($type, $value) { 451 $value = strtolower(preg_replace('/[^\w]+/', '', $value)); 452 $value = str_replace(' ', '_', $value); 453 $file = 'lib/plugins/statistics/ico/' . $type . '/' . $value . '.png'; 454 if($type == 'flags') { 455 $w = 18; 456 $h = 12; 457 } else { 458 $w = 16; 459 $h = 16; 460 } 461 if(file_exists(DOKU_INC . $file)) { 462 echo '<img src="' . DOKU_BASE . $file . '" alt="' . hsc($value) . '" width="' . $w . '" height="' . $h . '" />'; 463 } 464 } 465} 466