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/** 14 * All DokuWiki plugins to extend the admin function 15 * need to inherit from this class 16 */ 17class admin_plugin_statistics extends DokuWiki_Admin_Plugin { 18 public $dblink = null; 19 protected $opt = ''; 20 protected $from = ''; 21 protected $to = ''; 22 protected $start = ''; 23 protected $tlimit = ''; 24 25 /** 26 * Available statistic pages 27 */ 28 protected $pages = array('dashboard','page','referer','newreferer', 29 'outlinks','searchengines','searchphrases', 30 'searchwords', 'internalsearchphrases', 31 'internalsearchwords','browsers','os', 32 'countries','resolution'); 33 34 /** 35 * Initialize the helper 36 */ 37 public function __construct() { 38 $this->hlp = plugin_load('helper','statistics'); 39 } 40 41 /** 42 * Access for managers allowed 43 */ 44 public function forAdminOnly(){ 45 return false; 46 } 47 48 /** 49 * return sort order for position in admin menu 50 */ 51 public function getMenuSort() { 52 return 350; 53 } 54 55 /** 56 * handle user request 57 */ 58 public function handle() { 59 $this->opt = preg_replace('/[^a-z]+/','',$_REQUEST['opt']); 60 if(!in_array($this->opt,$this->pages)) $this->opt = 'dashboard'; 61 62 $this->start = (int) $_REQUEST['s']; 63 $this->setTimeframe($_REQUEST['f'],$_REQUEST['t']); 64 } 65 66 /** 67 * set limit clause 68 */ 69 public function setTimeframe($from,$to){ 70 // fixme add better sanity checking here: 71 $from = preg_replace('/[^\d\-]+/','',$from); 72 $to = preg_replace('/[^\d\-]+/','',$to); 73 if(!$from) $from = date('Y-m-d'); 74 if(!$to) $to = date('Y-m-d'); 75 76 //setup limit clause 77 $tlimit = "A.dt >= '$from 00:00:00' AND A.dt <= '$to 23:59:59'"; 78 $this->tlimit = $tlimit; 79 $this->from = $from; 80 $this->to = $to; 81 } 82 83 /** 84 * Output the Statistics 85 */ 86 function html() { 87 echo '<h1>Access Statistics</h1>'; 88 $this->html_timeselect(); 89 90 $method = 'html_'.$this->opt; 91 if(method_exists($this,$method)){ 92 echo '<div class="plg_stats_'.$this->opt.'">'; 93 echo '<h2>'.$this->getLang($this->opt).'</h2>'; 94 $this->$method(); 95 echo '</div>'; 96 } 97 } 98 99 /** 100 * Return the TOC 101 * 102 * @return array 103 */ 104 function getTOC(){ 105 $toc = array(); 106 foreach($this->pages as $page){ 107 $toc[] = array( 108 'link' => '?do=admin&page=statistics&opt='.$page.'&f='.$this->from.'&t='.$this->to, 109 'title' => $this->getLang($page), 110 'level' => 1, 111 'type' => 'ul' 112 ); 113 } 114 return $toc; 115 } 116 117 /** 118 * Outputs pagination links 119 * 120 * @fixme does this still work? 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">previous page</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">next page</a>'; 136 } 137 echo '</div>'; 138 } 139 140 /** 141 * Print the time selection menu 142 */ 143 function html_timeselect(){ 144 $now = date('Y-m-d'); 145 $yday = date('Y-m-d',time()-(60*60*24)); 146 $week = date('Y-m-d',time()-(60*60*24*7)); 147 $month = date('Y-m-d',time()-(60*60*24*30)); 148 149 echo '<div class="plg_stats_timeselect">'; 150 echo '<span>Select the timeframe:</span>'; 151 echo '<ul>'; 152 153 echo '<li>'; 154 echo '<a href="?do=admin&page=statistics&opt='.$this->opt.'&f='.$now.'&t='.$now.'">'; 155 echo 'today'; 156 echo '</a>'; 157 echo '</li>'; 158 159 echo '<li>'; 160 echo '<a href="?do=admin&page=statistics&opt='.$this->opt.'&f='.$yday.'&t='.$yday.'">'; 161 echo 'yesterday'; 162 echo '</a>'; 163 echo '</li>'; 164 165 echo '<li>'; 166 echo '<a href="?do=admin&page=statistics&opt='.$this->opt.'&f='.$week.'&t='.$now.'">'; 167 echo 'last 7 days'; 168 echo '</a>'; 169 echo '</li>'; 170 171 echo '<li>'; 172 echo '<a href="?do=admin&page=statistics&opt='.$this->opt.'&f='.$month.'&t='.$now.'">'; 173 echo 'last 30 days'; 174 echo '</a>'; 175 echo '</li>'; 176 177 echo '</ul>'; 178 179 180 echo '<form action="" method="get">'; 181 echo '<input type="hidden" name="do" value="admin" />'; 182 echo '<input type="hidden" name="page" value="statistics" />'; 183 echo '<input type="hidden" name="opt" value="'.$this->opt.'" />'; 184 echo '<input type="text" name="f" value="'.$this->from.'" class="edit" />'; 185 echo '<input type="text" name="t" value="'.$this->to.'" class="edit" />'; 186 echo '<input type="submit" value="go" class="button" />'; 187 echo '</form>'; 188 189 echo '</div>'; 190 } 191 192 193 /** 194 * Print an introductionary screen 195 */ 196 function html_dashboard(){ 197 echo '<p>This page gives you a quick overview on what is happening in your Wiki. For detailed lists 198 choose a topic from the list.</p>'; 199 200 // general info 201 echo '<div class="plg_stats_top">'; 202 $result = $this->hlp->Query()->aggregate($this->tlimit); 203 echo '<ul>'; 204 foreach(array('pageviews','sessions','visitors','users','logins','bouncerate','timespent','avgpages','newvisitors') as $name){ 205 echo '<li><div class="li">'.sprintf($this->getLang('dash_'.$name),$result[$name]).'</div></li>'; 206 } 207 echo '</ul>'; 208 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=trend&f='.$this->from.'&t='.$this->to.'" />'; 209 echo '</div>'; 210 211 212 // top pages today 213 echo '<div>'; 214 echo '<h2>Most popular pages</h2>'; 215 $result = $this->hlp->Query()->pages($this->tlimit,$this->start,15); 216 $this->html_resulttable($result); 217 echo '<a href="?do=admin&page=statistics&opt=page&f='.$this->from.'&t='.$this->to.'" class="more">more</a>'; 218 echo '</div>'; 219 220 // top referer today 221 echo '<div>'; 222 echo '<h2>Newest incoming links</h2>'; 223 $result = $this->hlp->Query()->newreferer($this->tlimit,$this->start,15); 224 $this->html_resulttable($result); 225 echo '<a href="?do=admin&page=statistics&opt=newreferer&f='.$this->from.'&t='.$this->to.'" class="more">more</a>'; 226 echo '</div>'; 227 228 // top searches today 229 echo '<div>'; 230 echo '<h2>Top search phrases</h2>'; 231 $result = $this->hlp->Query()->searchphrases($this->tlimit,$this->start,15); 232 $this->html_resulttable($result); 233 echo '<a href="?do=admin&page=statistics&opt=searchphrases&f='.$this->from.'&t='.$this->to.'" class="more">more</a>'; 234 echo '</div>'; 235 } 236 237 function html_countries(){ 238 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=countries&f='.$this->from.'&t='.$this->to.'" />'; 239 $result = $this->hlp->Query()->countries($this->tlimit,$this->start,150); 240 $this->html_resulttable($result,'',150); 241 } 242 243 function html_page(){ 244 $result = $this->hlp->Query()->pages($this->tlimit,$this->start,150); 245 $this->html_resulttable($result,'',150); 246 } 247 248 function html_browsers(){ 249 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=browsers&f='.$this->from.'&t='.$this->to.'" />'; 250 $result = $this->hlp->Query()->browsers($this->tlimit,$this->start,150,true); 251 $this->html_resulttable($result,'',150); 252 } 253 254 function html_os(){ 255 $result = $this->hlp->Query()->os($this->tlimit,$this->start,150,true); 256 $this->html_resulttable($result,'',150); 257 } 258 259 function html_referer(){ 260 $result = $this->hlp->Query()->aggregate($this->tlimit); 261 262 $all = $result['search']+$result['external']+$result['direct']; 263 264 if($all){ 265 printf("<p>Of all %d external visits, %d (%.1f%%) were bookmarked (direct) accesses, 266 %d (%.1f%%) came from search engines and %d (%.1f%%) were referred through 267 links from other pages.</p>",$all,$result['direct'],(100*$result['direct']/$all), 268 $result['search'],(100*$result['search']/$all),$result['external'], 269 (100*$result['external']/$all)); 270 } 271 272 $result = $this->hlp->Query()->referer($this->tlimit,$this->start,150); 273 $this->html_resulttable($result,'',150); 274 } 275 276 function html_newreferer(){ 277 echo '<p>The following incoming links where first logged in the selected time frame, 278 and have never been seen before.</p>'; 279 280 $result = $this->hlp->Query()->newreferer($this->tlimit,$this->start,150); 281 $this->html_resulttable($result,'',150); 282 } 283 284 function html_outlinks(){ 285 $result = $this->hlp->Query()->outlinks($this->tlimit,$this->start,150); 286 $this->html_resulttable($result,'',150); 287 } 288 289 function html_searchphrases(){ 290 $result = $this->hlp->Query()->searchphrases(true,$this->tlimit,$this->start,150); 291 $this->html_resulttable($result,'',150); 292 } 293 294 function html_searchwords(){ 295 $result = $this->hlp->Query()->searchwords(true,$this->tlimit,$this->start,150); 296 $this->html_resulttable($result,'',150); 297 } 298 299 function html_internalsearchphrases(){ 300 $result = $this->hlp->Query()->searchphrases(false,$this->tlimit,$this->start,150); 301 $this->html_resulttable($result,'',150); 302 } 303 304 function html_internalsearchwords(){ 305 $result = $this->hlp->Query()->searchwords(false,$this->tlimit,$this->start,150); 306 $this->html_resulttable($result,'',150); 307 } 308 309 function html_searchengines(){ 310 $result = $this->hlp->Query()->searchengines($this->tlimit,$this->start,150); 311 $this->html_resulttable($result,'',150); 312 } 313 314 315 function html_resolution(){ 316 317 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=resolution&f='.$this->from.'&t='.$this->to.'" />'; 318 319 echo '<p>While the data above gives you some info about the resolution your visitors use, it does not tell you 320 much about about the real size of their browser windows. The graphic below shows the size distribution of 321 the view port (document area) of your visitor\'s browsers. Please note that this data can not be logged 322 in all browsers. Because users may resize their browser window while browsing your site the statistics may 323 be flawed. Take it with a grain of salt.</p>'; 324 325 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=viewport&f='.$this->from.'&t='.$this->to.'" />'; 326 327 $result = $this->hlp->Query()->resolution($this->tlimit,$this->start,150); 328 $this->html_resulttable($result,'',150); 329 330 331 } 332 333 334 /** 335 * Display a result in a HTML table 336 */ 337 function html_resulttable($result,$header='',$pager=0){ 338 echo '<table>'; 339 if(is_array($header)){ 340 echo '<tr>'; 341 foreach($header as $h){ 342 echo '<th>'.hsc($h).'</th>'; 343 } 344 echo '</tr>'; 345 } 346 347 $count = 0; 348 if(is_array($result)) foreach($result as $row){ 349 echo '<tr>'; 350 foreach($row as $k => $v){ 351 echo '<td class="plg_stats_X'.$k.'">'; 352 if($k == 'page'){ 353 echo '<a href="'.wl($v).'" class="wikilink1">'; 354 echo hsc($v); 355 echo '</a>'; 356 }elseif($k == 'url'){ 357 $url = hsc($v); 358 $url = preg_replace('/^https?:\/\/(www\.)?/','',$url); 359 if(strlen($url) > 45){ 360 $url = substr($url,0,30).' … '.substr($url,-15); 361 } 362 echo '<a href="'.$v.'" class="urlextern">'; 363 echo $url; 364 echo '</a>'; 365 }elseif($k == 'ilookup'){ 366 echo '<a href="'.wl('',array('id'=>$v,'do'=>'search')).'">Search</a>'; 367 }elseif($k == 'lookup'){ 368 echo '<a href="http://www.google.com/search?q='.rawurlencode($v).'">'; 369 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/search/google.png" alt="lookup in Google" border="0" />'; 370 echo '</a> '; 371 372 echo '<a href="http://search.yahoo.com/search?p='.rawurlencode($v).'">'; 373 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/search/yahoo.png" alt="lookup in Yahoo" border="0" />'; 374 echo '</a> '; 375 376 echo '<a href="http://search.msn.com/results.aspx?q='.rawurlencode($v).'">'; 377 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/search/msn.png" alt="lookup in MSN Live" border="0" />'; 378 echo '</a> '; 379 380 }elseif($k == 'engine'){ 381 include_once(dirname(__FILE__).'/inc/search_engines.php'); 382 echo $SearchEnginesHashLib[$v]; 383 }elseif($k == 'bflag'){ 384 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/browser/'.strtolower(preg_replace('/[^\w]+/','',$v)).'.png" alt="'.hsc($v).'" />'; 385 }elseif($k == 'osflag'){ 386 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/os/'.strtolower(preg_replace('/[^\w]+/','',$v)).'.png" alt="'.hsc($v).'" />'; 387 }elseif($k == 'cflag'){ 388 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/flags/'.hsc($v).'.png" alt="'.hsc($v).'" width="18" height="12" />'; 389 }elseif($k == 'html'){ 390 echo $v; 391 }else{ 392 echo hsc($v); 393 } 394 echo '</td>'; 395 } 396 echo '</tr>'; 397 398 if($pager && ($count == $pager)) break; 399 $count++; 400 } 401 echo '</table>'; 402 403 if($pager) $this->html_pager($pager,count($result) > $pager); 404 } 405 406} 407