1<?php 2/** 3 * statistics plugin 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <gohr@cosmocode.de> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 13require_once(DOKU_PLUGIN.'admin.php'); 14 15/** 16 * All DokuWiki plugins to extend the admin function 17 * need to inherit from this class 18 */ 19class admin_plugin_statistics extends DokuWiki_Admin_Plugin { 20 var $dblink = null; 21 var $opt = ''; 22 var $from = ''; 23 var $to = ''; 24 var $start = ''; 25 var $tlimit = ''; 26 27 /** 28 * return some info 29 */ 30 function getInfo(){ 31 return confToHash(dirname(__FILE__).'/info.txt'); 32 } 33 34 /** 35 * Access for managers allowed 36 */ 37 function forAdminOnly(){ 38 return false; 39 } 40 41 /** 42 * return sort order for position in admin menu 43 */ 44 function getMenuSort() { 45 return 150; 46 } 47 48 /** 49 * handle user request 50 */ 51 function handle() { 52 $this->opt = preg_replace('/[^a-z]+/','',$_REQUEST['opt']); 53 54 $this->start = (int) $_REQUEST['s']; 55 56 // fixme add better sanity checking here: 57 $this->from = preg_replace('/[^\d\-]+/','',$_REQUEST['f']); 58 $this->to = preg_replace('/[^\d\-]+/','',$_REQUEST['t']); 59 if(!$this->from) $this->from = date('Y-m-d'); 60 if(!$this->to) $this->to = date('Y-m-d'); 61 62 //setup limit clause 63 if($this->from != $this->to){ 64 $this->tlimit = "DATE(A.dt) >= DATE('".$this->from."') AND DATE(A.dt) <= DATE('".$this->to."')"; 65 }else{ 66 $this->tlimit = "DATE(A.dt) = DATE('".$this->from."')"; 67 } 68 } 69 70 /** 71 * fixme build statistics here 72 */ 73 function html() { 74 $this->html_toc(); 75 echo '<h1>Access Statistics</h1>'; 76 $this->html_timeselect(); 77 78 switch($this->opt){ 79 case 'country': 80 $this->html_country(); 81 break; 82 case 'page': 83 $this->html_page(); 84 break; 85 case 'referer': 86 $this->html_referer(); 87 break; 88 default: 89 $this->html_dashboard(); 90 } 91 } 92 93 function html_toc(){ 94 echo '<div class="toc">'; 95 echo '<div class="tocheader toctoggle" id="toc__header">'; 96 echo 'Detailed Statistics'; 97 echo '</div>'; 98 echo '<div id="toc__inside">'; 99 echo '<ul class="toc">'; 100 101 echo '<li><div class="li">'; 102 echo '<a href="?do=admin&page=statistics&opt=&f='.$this->from.'&t='.$this->to.'&s='.$this->start.'">Dashboard</a>'; 103 echo '</div></li>'; 104 105 echo '<li><div class="li">'; 106 echo '<a href="?do=admin&page=statistics&opt=page&f='.$this->from.'&t='.$this->to.'&s='.$this->start.'">Pages</a>'; 107 echo '</div></li>'; 108 109 echo '<li><div class="li">'; 110 echo '<a href="?do=admin&page=statistics&opt=referer&f='.$this->from.'&t='.$this->to.'&s='.$this->start.'">Incoming Links</a>'; 111 echo '</div></li>'; 112 113 echo '<li><div class="li">'; 114 echo '<a href="?do=admin&page=statistics&opt=country&f='.$this->from.'&t='.$this->to.'&s='.$this->start.'">Countries</a>'; 115 echo '</div></li>'; 116 117 echo '</ul>'; 118 echo '</div>'; 119 echo '</div>'; 120 } 121 122 /** 123 * Print the time selection menu 124 */ 125 function html_timeselect(){ 126 $now = date('Y-m-d'); 127 $yday = date('Y-m-d',time()-(60*60*24)); 128 $week = date('Y-m-d',time()-(60*60*24*7)); 129 $month = date('Y-m-d',time()-(60*60*24*30)); 130 131 echo '<div class="plg_stats_timeselect">'; 132 echo '<span>Select the timeframe:</span>'; 133 echo '<ul>'; 134 135 echo '<li>'; 136 echo '<a href="?do=admin&page=statistics&opt='.$this->opt.'&f='.$now.'&t='.$now.'&s='.$this->start.'">'; 137 echo 'today'; 138 echo '</a>'; 139 echo '</li>'; 140 141 echo '<li>'; 142 echo '<a href="?do=admin&page=statistics&opt='.$this->opt.'&f='.$yday.'&t='.$yday.'&s='.$this->start.'">'; 143 echo 'yesterday'; 144 echo '</a>'; 145 echo '</li>'; 146 147 echo '<li>'; 148 echo '<a href="?do=admin&page=statistics&opt='.$this->opt.'&f='.$week.'&t='.$now.'&s='.$this->start.'">'; 149 echo 'last 7 days'; 150 echo '</a>'; 151 echo '</li>'; 152 153 echo '<li>'; 154 echo '<a href="?do=admin&page=statistics&opt='.$this->opt.'&f='.$month.'&t='.$now.'&s='.$this->start.'">'; 155 echo 'last 30 days'; 156 echo '</a>'; 157 echo '</li>'; 158 159 echo '</ul>'; 160 161 162 echo '<form action="" method="get">'; 163 echo '<input type="hidden" name="do" value="admin" />'; 164 echo '<input type="hidden" name="page" value="statistics" />'; 165 echo '<input type="hidden" name="opt" value="'.$this->opt.'" />'; 166 echo '<input type="hidden" name="s" value="'.$this->start.'" />'; 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 '</div>'; 173 } 174 175 176 /** 177 * Print an introductionary screen 178 */ 179 function html_dashboard(){ 180 echo '<p>This page gives you a quick overview on what is happening in your Wiki. For detailed lists 181 choose a topic from the list.</p>'; 182 183 184 echo '<div class="plg_stats_dashboard">'; 185 186 // general info 187 echo '<div class="plg_stats_top">'; 188 $result = $this->sql_aggregate($this->tlimit); 189 echo '<ul>'; 190 echo '<li><span>'.$result['pageviews'].'</span> page views</li>'; 191 echo '<li><span>'.$result['sessions'].'</span> visitors (sessions)</li>'; 192 echo '<li><span>'.$result['users'].'</span> logged in users</li>'; 193 194 echo '</ul>'; 195 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=trend&f='.$this->from.'&t='.$this->to.'" />'; 196 echo '</div>'; 197 198 199 // top pages today 200 echo '<div>'; 201 echo '<h2>Most popular pages</h2>'; 202 $result = $this->sql_pages($this->tlimit,$this->start,15); 203 $this->html_resulttable($result); 204 echo '</div>'; 205 206 // top referer today 207 echo '<div>'; 208 echo '<h2>Top incoming links</h2>'; 209 $result = $this->sql_referer($this->tlimit,$this->start,15); 210 $this->html_resulttable($result); 211 echo '</div>'; 212 213 // top countries today 214 echo '<div>'; 215 echo '<h2>Visitor\'s top countries</h2>'; 216 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=country&f='.$this->from.'&t='.$this->to.'" />'; 217// $result = $this->sql_countries($this->tlimit,$this->start,15); 218// $this->html_resulttable($result,array('','Countries','Count')); 219 echo '</div>'; 220 221 echo '</div>'; 222 } 223 224 function html_country(){ 225 echo '<div class="plg_stats_full">'; 226 echo '<h2>Visitor\'s Countries</h2>'; 227 $result = $this->sql_countries($this->tlimit,$this->start,150); 228 $this->html_resulttable($result); 229 echo '</div>'; 230 } 231 232 function html_page(){ 233 echo '<div class="plg_stats_full">'; 234 echo '<h2>Popular Pages</h2>'; 235 $result = $this->sql_pages($this->tlimit,$this->start,150); 236 $this->html_resulttable($result); 237 echo '</div>'; 238 } 239 240 function html_referer(){ 241 echo '<div class="plg_stats_full">'; 242 echo '<h2>Incoming Links</h2>'; 243 $result = $this->sql_aggregate($this->tlimit); 244 245 $all = $result['search']+$result['external']+$result['direct']; 246 247 printf("<p>Of all %d external visits, %d (%.1f%%) were bookmarked (direct) accesses, 248 %d (%.1f%%) came from search engines and %d (%.1f%%) were referred through 249 links from other pages.</p>",$all,$result['direct'],(100*$result['direct']/$all), 250 $result['search'],(100*$result['search']/$all),$result['external'], 251 (100*$result['external']/$all)); 252 253 $result = $this->sql_referer($this->tlimit,$this->start,150); 254 $this->html_resulttable($result); 255 echo '</div>'; 256 } 257 258 259 260 /** 261 * Display a result in a HTML table 262 */ 263 function html_resulttable($result,$header=''){ 264 echo '<table>'; 265 if(is_array($header)){ 266 echo '<tr>'; 267 foreach($header as $h){ 268 echo '<th>'.hsc($h).'</th>'; 269 } 270 echo '</tr>'; 271 } 272 273 foreach($result as $row){ 274 echo '<tr>'; 275 foreach($row as $k => $v){ 276 echo '<td class="plg_stats_X'.$k.'">'; 277 if($k == 'page'){ 278 echo '<a href="'.wl($v).'" class="wikilink1">'; 279 echo hsc($v); 280 echo '</a>'; 281 }elseif($k == 'url'){ 282 $url = hsc($v); 283 if(strlen($url) > 45){ 284 $url = substr($url,0,30).' … '.substr($url,-15); 285 } 286 echo '<a href="'.$v.'" class="urlextern">'; 287 echo $url; 288 echo '</a>'; 289 }elseif($k == 'html'){ 290 echo $v; 291 }elseif($k == 'cflag'){ 292 echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/flags/'.hsc($v).'.png" alt="'.hsc($v).'" width="18" height="12"/>'; 293 }else{ 294 echo hsc($v); 295 } 296 echo '</td>'; 297 } 298 echo '</tr>'; 299 } 300 echo '</table>'; 301 } 302 303 /** 304 * Create an image 305 */ 306 function img_build($img){ 307 include(dirname(__FILE__).'/inc/AGC.class.php'); 308 309 switch($img){ 310 case 'country': 311 // build top countries + other 312 $result = $this->sql_countries($this->tlimit,$this->start,0); 313 $data = array(); 314 $top = 0; 315 foreach($result as $row){ 316 if($top < 7){ 317 $data[$row['country']] = $row['cnt']; 318 }else{ 319 $data['other'] += $row['cnt']; 320 } 321 $top++; 322 } 323 $pie = new AGC(300, 200); 324 $pie->setProp("showkey",true); 325 $pie->setProp("showval",false); 326 $pie->setProp("showgrid",false); 327 $pie->setProp("type","pie"); 328 $pie->setProp("keyinfo",1); 329 $pie->setProp("keysize",8); 330 $pie->setProp("keywidspc",-50); 331 $pie->setProp("key",array_keys($data)); 332 $pie->addBulkPoints(array_values($data)); 333 @$pie->graph(); 334 $pie->showGraph(); 335 break; 336 case 'trend': 337 $hours = ($this->from == $this->to); 338 $result = $this->sql_trend($this->tlimit,$hours); 339 $data1 = array(); 340 $data2 = array(); 341 342 $graph = new AGC(400, 150); 343 $graph->setProp("type","bar"); 344 $graph->setProp("showgrid",false); 345 $graph->setProp("barwidth",.8); 346 $graph->setColor('color',0,'blue'); 347 $graph->setColor('color',1,'red'); 348 349 if($hours){ 350 //preset $hours 351 for($i=0;$i<24;$i++){ 352 $data1[$i] = 0; 353 $data2[$i] = 0; 354 $graph->setProp("scale",array(' 0h',' 4h',' 8h',' 12h',' 16h',' 20h',' 24h')); 355 } 356 }else{ 357 $graph->setProp("scale",array(next(array_keys($data1)),$this->to)); 358 } 359 360 foreach($result as $row){ 361 $data1[$row['time']] = $row['pageviews']; 362 $data2[$row['time']] = $row['sessions']; 363 } 364 365 foreach($data1 as $key => $val){ 366 $graph->addPoint($val,$key,0); 367 } 368 foreach($data2 as $key => $val){ 369 $graph->addPoint($val,$key,1); 370 } 371 372 @$graph->graph(); 373 $graph->showGraph(); 374 375 default: 376 $this->sendGIF(); 377 } 378 } 379 380 381 /** 382 * Return some aggregated statistics 383 */ 384 function sql_aggregate($tlimit){ 385 $data = array(); 386 387 $sql = "SELECT ref_type, COUNT(*) as cnt 388 FROM ".$this->getConf('db_prefix')."access as A 389 WHERE $tlimit 390 AND ua_type = 'browser' 391 GROUP BY ref_type"; 392 $result = $this->runSQL($sql); 393 394 foreach($result as $row){ 395 if($row['ref_type'] == 'search') $data['search'] = $row['cnt']; 396 if($row['ref_type'] == 'external') $data['external'] = $row['cnt']; 397 if($row['ref_type'] == 'internal') $data['internal'] = $row['cnt']; 398 if($row['ref_type'] == '') $data['direct'] = $row['cnt']; 399 } 400 401 $sql = "SELECT COUNT(DISTINCT session) as sessions, 402 COUNT(session) as views, 403 COUNT(DISTINCT user) as users 404 FROM ".$this->getConf('db_prefix')."access as A 405 WHERE $tlimit 406 AND ua_type = 'browser'"; 407 $result = $this->runSQL($sql); 408 409 $data['users'] = $result[0]['users'] - 1; // subtract empty user 410 $data['sessions'] = $result[0]['sessions']; 411 $data['pageviews'] = $result[0]['views']; 412 413 $sql = "SELECT COUNT(id) as robots 414 FROM ".$this->getConf('db_prefix')."access as A 415 WHERE $tlimit 416 AND ua_type = 'robot'"; 417 $result = $this->runSQL($sql); 418 $data['robots'] = $result[0]['robots']; 419 420 return $data; 421 } 422 423 function sql_trend($tlimit,$hours=false){ 424 if($hours){ 425 $sql = "SELECT HOUR(dt) as time, 426 COUNT(DISTINCT session) as sessions, 427 COUNT(session) as pageviews 428 FROM ".$this->getConf('db_prefix')."access as A 429 WHERE $tlimit 430 AND ua_type = 'browser' 431 GROUP BY HOUR(dt) 432 ORDER BY time"; 433 }else{ 434 $sql = "SELECT DATE(dt) as time, 435 COUNT(DISTINCT session) as sessions, 436 COUNT(session) as pageviews 437 FROM ".$this->getConf('db_prefix')."access as A 438 WHERE $tlimit 439 AND ua_type = 'browser' 440 GROUP BY DATE(dt) 441 ORDER BY time"; 442 } 443 return $this->runSQL($sql); 444 } 445 446 function sql_pages($tlimit,$start=0,$limit=20){ 447 $sql = "SELECT COUNT(*) as cnt, page 448 FROM ".$this->getConf('db_prefix')."access as A 449 WHERE $tlimit 450 AND ua_type = 'browser' 451 GROUP BY page 452 ORDER BY cnt DESC, page". 453 $this->sql_limit($start,$limit); 454 return $this->runSQL($sql); 455 } 456 457 function sql_referer($tlimit,$start=0,$limit=20){ 458 $sql = "SELECT COUNT(*) as cnt, ref as url 459 FROM ".$this->getConf('db_prefix')."access as A 460 WHERE $tlimit 461 AND ua_type = 'browser' 462 AND ref_type = 'external' 463 GROUP BY ref_md5 464 ORDER BY cnt DESC, url". 465 $this->sql_limit($start,$limit); 466 return $this->runSQL($sql); 467 } 468 469 function sql_countries($tlimit,$start=0,$limit=20){ 470 $sql = "SELECT COUNT(*) as cnt, B.code AS cflag, B.country 471 FROM ".$this->getConf('db_prefix')."access as A, 472 ".$this->getConf('db_prefix')."iplocation as B 473 WHERE $tlimit 474 AND A.ip = B.ip 475 GROUP BY B.country 476 ORDER BY cnt DESC, B.country". 477 $this->sql_limit($start,$limit); 478 return $this->runSQL($sql); 479 } 480 481 /** 482 * Builds a limit clause 483 */ 484 function sql_limit($start,$limit){ 485 $start = (int) $start; 486 $limit = (int) $limit; 487 if($limit){ 488 return " LIMIT $start,$limit"; 489 }elseif($start){ 490 return " OFFSET $start"; 491 } 492 return ''; 493 } 494 495 /** 496 * Return a link to the DB, opening the connection if needed 497 */ 498 function dbLink(){ 499 // connect to DB if needed 500 if(!$this->dblink){ 501 $this->dblink = mysql_connect($this->getConf('db_server'), 502 $this->getConf('db_user'), 503 $this->getConf('db_password')); 504 if(!$this->dblink){ 505 msg('DB Error: connection failed',-1); 506 return null; 507 } 508 // set utf-8 509 if(!mysql_db_query($this->getConf('db_database'),'set names utf8',$this->dblink)){ 510 msg('DB Error: could not set UTF-8 ('.mysql_error($this->dblink).')',-1); 511 return null; 512 } 513 } 514 return $this->dblink; 515 } 516 517 /** 518 * Simple function to run a DB query 519 */ 520 function runSQL($sql_string) { 521 $link = $this->dbLink(); 522 523 $result = mysql_db_query($this->conf['db_database'],$sql_string,$link); 524 if(!$result){ 525 msg('DB Error: '.mysql_error($link).' '.hsc($sql_string),-1); 526 return null; 527 } 528 529 $resultarray = array(); 530 531 //mysql_db_query returns 1 on a insert statement -> no need to ask for results 532 if ($result != 1) { 533 for($i=0; $i< mysql_num_rows($result); $i++) { 534 $temparray = mysql_fetch_assoc($result); 535 $resultarray[]=$temparray; 536 } 537 mysql_free_result($result); 538 } 539 540 if (mysql_insert_id($link)) { 541 $resultarray = mysql_insert_id($link); //give back ID on insert 542 } 543 544 return $resultarray; 545 } 546 547 /** 548 * Returns a short name for a User Agent and sets type, version and os info 549 */ 550 function ua_info($ua,&$type,&$ver,&$os){ 551 $ua = strtr($ua,' +','__'); 552 $ua = strtolower($ua); 553 554 // common browsers 555 $regvermsie = '/msie([+_ ]|)([\d\.]*)/i'; 556 $regvernetscape = '/netscape.?\/([\d\.]*)/i'; 557 $regverfirefox = '/firefox\/([\d\.]*)/i'; 558 $regversvn = '/svn\/([\d\.]*)/i'; 559 $regvermozilla = '/mozilla(\/|)([\d\.]*)/i'; 560 $regnotie = '/webtv|omniweb|opera/i'; 561 $regnotnetscape = '/gecko|compatible|opera|galeon|safari/i'; 562 563 $name = ''; 564 # IE ? 565 if(preg_match($regvermsie,$ua,$m) && !preg_match($regnotie,$ua)){ 566 $type = 'browser'; 567 $ver = $m[2]; 568 $name = 'msie'; 569 } 570 # Firefox ? 571 elseif (preg_match($regverfirefox,$ua,$m)){ 572 $type = 'browser'; 573 $ver = $m[1]; 574 $name = 'firefox'; 575 } 576 # Subversion ? 577 elseif (preg_match($regversvn,$ua,$m)){ 578 $type = 'rcs'; 579 $ver = $m[1]; 580 $name = 'svn'; 581 } 582 # Netscape 6.x, 7.x ... ? 583 elseif (preg_match($regvernetscape,$ua,$m)){ 584 $type = 'browser'; 585 $ver = $m[1]; 586 $name = 'netscape'; 587 } 588 # Netscape 3.x, 4.x ... ? 589 elseif(preg_match($regvermozilla,$ua,$m) && !preg_match($regnotnetscape,$ua)){ 590 $type = 'browser'; 591 $ver = $m[2]; 592 $name = 'netscape'; 593 }else{ 594 include(dirname(__FILE__).'/inc/browsers.php'); 595 foreach($BrowsersSearchIDOrder as $regex){ 596 if(preg_match('/'.$regex.'/',$ua)){ 597 // it's a browser! 598 $type = 'browser'; 599 $name = strtolower($regex); 600 break; 601 } 602 } 603 } 604 605 // check OS for browsers 606 if($type == 'browser'){ 607 include(dirname(__FILE__).'/inc/operating_systems.php'); 608 foreach($OSSearchIDOrder as $regex){ 609 if(preg_match('/'.$regex.'/',$ua)){ 610 $os = $OSHashID[$regex]; 611 break; 612 } 613 } 614 615 } 616 617 // are we done now? 618 if($name) return $name; 619 620 include(dirname(__FILE__).'/inc/robots.php'); 621 foreach($RobotsSearchIDOrder as $regex){ 622 if(preg_match('/'.$regex.'/',$ua)){ 623 // it's a robot! 624 $type = 'robot'; 625 return strtolower($regex); 626 } 627 } 628 629 // dunno 630 return ''; 631 } 632 633 /** 634 * 635 * @fixme: put search engine queries in seperate table here 636 */ 637 function log_search($referer,&$type){ 638 $referer = strtr($referer,' +','__'); 639 $referer = strtolower($referer); 640 641 include(dirname(__FILE__).'/inc/search_engines.php'); 642 643 foreach($SearchEnginesSearchIDOrder as $regex){ 644 if(preg_match('/'.$regex.'/',$referer)){ 645 if(!$NotSearchEnginesKeys[$regex] || 646 !preg_match('/'.$NotSearchEnginesKeys[$regex].'/',$referer)){ 647 // it's a search engine! 648 $type = 'search'; 649 break; 650 } 651 } 652 } 653 if($type != 'search') return; // we're done here 654 655 #fixme now do the keyword magic! 656 } 657 658 /** 659 * Resolve IP to country/city 660 */ 661 function log_ip($ip){ 662 // check if IP already known and up-to-date 663 $sql = "SELECT ip 664 FROM ".$this->getConf('db_prefix')."iplocation 665 WHERE ip ='".addslashes($ip)."' 666 AND lastupd > DATE_SUB(CURDATE(),INTERVAL 30 DAY)"; 667 $result = $this->runSQL($sql); 668 if($result[0]['ip']) return; 669 670 $http = new DokuHTTPClient(); 671 $http->timeout = 10; 672 $data = $http->get('http://api.hostip.info/get_html.php?ip='.$ip); 673 674 if(preg_match('/^Country: (.*?) \((.*?)\)\nCity: (.*?)$/s',$data,$match)){ 675 $country = addslashes(trim($match[1])); 676 $code = addslashes(strtolower(trim($match[2]))); 677 $city = addslashes(trim($match[3])); 678 $host = addslashes(gethostbyaddr($ip)); 679 $ip = addslashes($ip); 680 681 $sql = "REPLACE INTO ".$this->getConf('db_prefix')."iplocation 682 SET ip = '$ip', 683 country = '$country', 684 code = '$code', 685 city = '$city', 686 host = '$host'"; 687 $this->runSQL($sql); 688 } 689 } 690 691 /** 692 * log a page access 693 * 694 * called from log.php 695 */ 696 function log_access(){ 697 if(!$_REQUEST['p']) return; 698 699 # FIXME check referer against blacklist and drop logging for bad boys 700 701 // handle referer 702 $referer = trim($_REQUEST['r']); 703 if($referer){ 704 $ref = addslashes($referer); 705 $ref_md5 = ($ref) ? md5($referer) : ''; 706 if(strpos($referer,DOKU_URL) === 0){ 707 $ref_type = 'internal'; 708 }else{ 709 $ref_type = 'external'; 710 $this->log_search($referer,$ref_type); 711 } 712 }else{ 713 $ref = ''; 714 $ref_md5 = ''; 715 $ref_type = ''; 716 } 717 718 // handle user agent 719 $agent = trim($_SERVER['HTTP_USER_AGENT']); 720 721 $ua = addslashes($agent); 722 $ua_type = ''; 723 $ua_ver = ''; 724 $os = ''; 725 $ua_info = addslashes($this->ua_info($agent,$ua_type,$ua_ver,$os)); 726 727 $page = addslashes($_REQUEST['p']); 728 $ip = addslashes($_SERVER['REMOTE_ADDR']); 729 $sx = (int) $_REQUEST['sx']; 730 $sy = (int) $_REQUEST['sy']; 731 $vx = (int) $_REQUEST['vx']; 732 $vy = (int) $_REQUEST['vy']; 733 $user = addslashes($_SERVER['REMOTE_USER']); 734 $session = addslashes(session_id()); 735 736 $sql = "INSERT DELAYED INTO ".$this->getConf('db_prefix')."access 737 SET page = '$page', 738 ip = '$ip', 739 ua = '$ua', 740 ua_info = '$ua_info', 741 ua_type = '$ua_type', 742 ua_ver = '$ua_ver', 743 os = '$os', 744 ref = '$ref', 745 ref_md5 = '$ref_md5', 746 ref_type = '$ref_type', 747 screen_x = '$sx', 748 screen_y = '$sy', 749 view_x = '$vx', 750 view_y = '$vy', 751 user = '$user', 752 session = '$session'"; 753 $ok = $this->runSQL($sql); 754 if(is_null($ok)){ 755 global $MSG; 756 print_r($MSG); 757 } 758 759 // resolve the IP 760 $this->log_ip($_SERVER['REMOTE_ADDR']); 761 } 762 763 /** 764 * Just send a 1x1 pixel blank gif to the browser 765 * 766 * @called from log.php 767 * 768 * @author Andreas Gohr <andi@splitbrain.org> 769 * @author Harry Fuecks <fuecks@gmail.com> 770 */ 771 function sendGIF(){ 772 $img = base64_decode('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7'); 773 header('Content-Type: image/gif'); 774 header('Content-Length: '.strlen($img)); 775 header('Connection: Close'); 776 print $img; 777 flush(); 778 // Browser should drop connection after this 779 // Thinks it's got the whole image 780 } 781 782} 783