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