xref: /plugin/statistics/admin.php (revision 95eb68e61dacbcb716660f91eed66fc3cfa7c2a2)
11878f16fSAndreas Gohr<?php
21878f16fSAndreas Gohr/**
31878f16fSAndreas Gohr * statistics plugin
41878f16fSAndreas Gohr *
51878f16fSAndreas Gohr * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
61878f16fSAndreas Gohr * @author     Andreas Gohr <gohr@cosmocode.de>
71878f16fSAndreas Gohr */
81878f16fSAndreas Gohr
91878f16fSAndreas Gohr// must be run within Dokuwiki
101878f16fSAndreas Gohrif(!defined('DOKU_INC')) die();
111878f16fSAndreas Gohr
121878f16fSAndreas Gohrif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
131878f16fSAndreas Gohrrequire_once(DOKU_PLUGIN.'admin.php');
141878f16fSAndreas Gohr
151878f16fSAndreas Gohr/**
161878f16fSAndreas Gohr * All DokuWiki plugins to extend the admin function
171878f16fSAndreas Gohr * need to inherit from this class
181878f16fSAndreas Gohr */
191878f16fSAndreas Gohrclass admin_plugin_statistics extends DokuWiki_Admin_Plugin {
201878f16fSAndreas Gohr    var $dblink = null;
21264f1744SAndreas Gohr    var $opt    = '';
22264f1744SAndreas Gohr    var $from   = '';
23264f1744SAndreas Gohr    var $to     = '';
24*95eb68e6SAndreas Gohr    var $start  = '';
25264f1744SAndreas Gohr    var $tlimit = '';
261878f16fSAndreas Gohr
271878f16fSAndreas Gohr    /**
281878f16fSAndreas Gohr     * return some info
291878f16fSAndreas Gohr     */
301878f16fSAndreas Gohr    function getInfo(){
311878f16fSAndreas Gohr        return confToHash(dirname(__FILE__).'/info.txt');
321878f16fSAndreas Gohr    }
331878f16fSAndreas Gohr
341878f16fSAndreas Gohr    /**
351878f16fSAndreas Gohr     * Access for managers allowed
361878f16fSAndreas Gohr     */
371878f16fSAndreas Gohr    function forAdminOnly(){
381878f16fSAndreas Gohr        return false;
391878f16fSAndreas Gohr    }
401878f16fSAndreas Gohr
411878f16fSAndreas Gohr    /**
421878f16fSAndreas Gohr     * return sort order for position in admin menu
431878f16fSAndreas Gohr     */
441878f16fSAndreas Gohr    function getMenuSort() {
4514d99ec0SAndreas Gohr        return 150;
461878f16fSAndreas Gohr    }
471878f16fSAndreas Gohr
481878f16fSAndreas Gohr    /**
491878f16fSAndreas Gohr     * handle user request
501878f16fSAndreas Gohr     */
511878f16fSAndreas Gohr    function handle() {
52264f1744SAndreas Gohr        $this->opt = preg_replace('/[^a-z]+/','',$_REQUEST['opt']);
53*95eb68e6SAndreas Gohr
54*95eb68e6SAndreas Gohr        $this->start = (int) $_REQUEST['s'];
55*95eb68e6SAndreas Gohr
56264f1744SAndreas Gohr        // fixme add better sanity checking here:
57264f1744SAndreas Gohr        $this->from = preg_replace('/[^\d\-]+/','',$_REQUEST['f']);
58264f1744SAndreas Gohr        $this->to = preg_replace('/[^\d\-]+/','',$_REQUEST['t']);
59264f1744SAndreas Gohr        if(!$this->from) $this->from = date('Y-m-d');
60264f1744SAndreas Gohr        if(!$this->to) $this->to     = date('Y-m-d');
61264f1744SAndreas Gohr
62264f1744SAndreas Gohr        //setup limit clause
63264f1744SAndreas Gohr        if($this->from != $this->to){
64264f1744SAndreas Gohr            $this->tlimit = "DATE(A.dt) >= DATE('".$this->from."') AND DATE(A.dt) <= DATE('".$this->to."')";
65264f1744SAndreas Gohr        }else{
66264f1744SAndreas Gohr            $this->tlimit = "DATE(A.dt) = DATE('".$this->from."')";
67264f1744SAndreas Gohr        }
681878f16fSAndreas Gohr    }
691878f16fSAndreas Gohr
701878f16fSAndreas Gohr    /**
7194171ff3SAndreas Gohr     * fixme build statistics here
721878f16fSAndreas Gohr     */
731878f16fSAndreas Gohr    function html() {
7414d99ec0SAndreas Gohr        // fixme build a navigation menu in a TOC here
7514d99ec0SAndreas Gohr
76264f1744SAndreas Gohr        echo '<h1>Access Statistics</h1>';
77264f1744SAndreas Gohr        $this->html_timeselect();
78264f1744SAndreas Gohr
79264f1744SAndreas Gohr        switch($this->opt){
8014d99ec0SAndreas Gohr
8114d99ec0SAndreas Gohr            default:
8214d99ec0SAndreas Gohr                echo $this->html_dashboard();
8314d99ec0SAndreas Gohr        }
8414d99ec0SAndreas Gohr    }
8514d99ec0SAndreas Gohr
86264f1744SAndreas Gohr    /**
87264f1744SAndreas Gohr     * Print the time selection menu
88264f1744SAndreas Gohr     */
8914d99ec0SAndreas Gohr    function html_timeselect(){
90264f1744SAndreas Gohr        $now   = date('Y-m-d');
91264f1744SAndreas Gohr        $yday  = date('Y-m-d',time()-(60*60*24));
92264f1744SAndreas Gohr        $week  = date('Y-m-d',time()-(60*60*24*7));
93264f1744SAndreas Gohr        $month = date('Y-m-d',time()-(60*60*24*30));
9414d99ec0SAndreas Gohr
95264f1744SAndreas Gohr        echo '<div class="plg_stats_timeselect">';
96264f1744SAndreas Gohr        echo '<span>Select the timeframe:</span>';
97264f1744SAndreas Gohr        echo '<ul>';
98264f1744SAndreas Gohr
99264f1744SAndreas Gohr        echo '<li>';
100*95eb68e6SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$now.'&amp;t='.$now.'&amp;s='.$this->start.'">';
101264f1744SAndreas Gohr        echo 'today';
102264f1744SAndreas Gohr        echo '</a>';
103264f1744SAndreas Gohr        echo '</li>';
104264f1744SAndreas Gohr
105264f1744SAndreas Gohr        echo '<li>';
106*95eb68e6SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$yday.'&amp;t='.$yday.'&amp;s='.$this->start.'">';
107264f1744SAndreas Gohr        echo 'yesterday';
108264f1744SAndreas Gohr        echo '</a>';
109264f1744SAndreas Gohr        echo '</li>';
110264f1744SAndreas Gohr
111264f1744SAndreas Gohr        echo '<li>';
112*95eb68e6SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$week.'&amp;t='.$now.'&amp;s='.$this->start.'">';
113264f1744SAndreas Gohr        echo 'last 7 days';
114264f1744SAndreas Gohr        echo '</a>';
115264f1744SAndreas Gohr        echo '</li>';
116264f1744SAndreas Gohr
117264f1744SAndreas Gohr        echo '<li>';
118*95eb68e6SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$month.'&amp;t='.$now.'&amp;s='.$this->start.'">';
119264f1744SAndreas Gohr        echo 'last 30 days';
120264f1744SAndreas Gohr        echo '</a>';
121264f1744SAndreas Gohr        echo '</li>';
122264f1744SAndreas Gohr
123264f1744SAndreas Gohr        echo '</ul>';
124264f1744SAndreas Gohr
125264f1744SAndreas Gohr
126264f1744SAndreas Gohr        echo '<form action="" method="get">';
127264f1744SAndreas Gohr        echo '<input type="hidden" name="do" value="admin" />';
128264f1744SAndreas Gohr        echo '<input type="hidden" name="page" value="statistics" />';
129264f1744SAndreas Gohr        echo '<input type="hidden" name="opt" value="'.$this->opt.'" />';
130*95eb68e6SAndreas Gohr        echo '<input type="hidden" name="s" value="'.$this->start.'" />';
131264f1744SAndreas Gohr        echo '<input type="text" name="f" value="'.$this->from.'" class="edit" />';
132264f1744SAndreas Gohr        echo '<input type="text" name="t" value="'.$this->to.'" class="edit" />';
133264f1744SAndreas Gohr        echo '<input type="submit" value="go" class="button" />';
13414d99ec0SAndreas Gohr        echo '</form>';
135264f1744SAndreas Gohr
136264f1744SAndreas Gohr        echo '</div>';
13714d99ec0SAndreas Gohr    }
13814d99ec0SAndreas Gohr
13914d99ec0SAndreas Gohr
140f5f32cbfSAndreas Gohr    /**
141f5f32cbfSAndreas Gohr     * Print an introductionary screen
142f5f32cbfSAndreas Gohr     *
143f5f32cbfSAndreas Gohr     * @fixme the sql statements probably need to go into their own functions
144f5f32cbfSAndreas Gohr     *        to be reused in the syntax plugins to follow
145f5f32cbfSAndreas Gohr     */
14614d99ec0SAndreas Gohr    function html_dashboard(){
147264f1744SAndreas Gohr        echo '<div class="plg_stats_dashboard">';
148264f1744SAndreas Gohr
14914d99ec0SAndreas Gohr
15087d5e44bSAndreas Gohr        // top pages today
151264f1744SAndreas Gohr        echo '<div>';
152264f1744SAndreas Gohr        echo '<h2>Most popular pages</h2>';
153*95eb68e6SAndreas Gohr        $result = $this->sql_pages($this->tlimit,$this->start,15);
15487d5e44bSAndreas Gohr        $this->html_resulttable($result,array('Pages','Count'));
155264f1744SAndreas Gohr        echo '</div>';
15687d5e44bSAndreas Gohr
15787d5e44bSAndreas Gohr        // top referer today
158264f1744SAndreas Gohr        echo '<div>';
159264f1744SAndreas Gohr        echo '<h2>Top incoming links</h2>';
160*95eb68e6SAndreas Gohr        $result = $this->sql_referer($this->tlimit,$this->start,15);
16187d5e44bSAndreas Gohr        $this->html_resulttable($result,array('Incoming Links','Count'));
162264f1744SAndreas Gohr        echo '</div>';
16354f6c432SAndreas Gohr
16454f6c432SAndreas Gohr        // top countries today
165264f1744SAndreas Gohr        echo '<div>';
166264f1744SAndreas Gohr        echo '<h2>Visitor\'s top countries</h2>';
167*95eb68e6SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=country&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
168*95eb68e6SAndreas Gohr//        $result = $this->sql_countries($this->tlimit,$this->start,15);
169*95eb68e6SAndreas Gohr//        $this->html_resulttable($result,array('','Countries','Count'));
170264f1744SAndreas Gohr        echo '</div>';
171264f1744SAndreas Gohr
172264f1744SAndreas Gohr        echo '</div>';
17314d99ec0SAndreas Gohr    }
17414d99ec0SAndreas Gohr
17514d99ec0SAndreas Gohr    /**
17614d99ec0SAndreas Gohr     * Display a result in a HTML table
17714d99ec0SAndreas Gohr     */
17814d99ec0SAndreas Gohr    function html_resulttable($result,$header){
17914d99ec0SAndreas Gohr        echo '<table>';
18014d99ec0SAndreas Gohr        echo '<tr>';
18114d99ec0SAndreas Gohr        foreach($header as $h){
18214d99ec0SAndreas Gohr            echo '<th>'.hsc($h).'</th>';
18314d99ec0SAndreas Gohr        }
18414d99ec0SAndreas Gohr        echo '</tr>';
18514d99ec0SAndreas Gohr
18614d99ec0SAndreas Gohr        foreach($result as $row){
18714d99ec0SAndreas Gohr            echo '<tr>';
18814d99ec0SAndreas Gohr            foreach($row as $k => $v){
18914d99ec0SAndreas Gohr                echo '<td class="stats_'.$k.'">';
19014d99ec0SAndreas Gohr                if($k == 'page'){
19114d99ec0SAndreas Gohr                    echo '<a href="'.wl($v).'" class="wikilink1">';
19214d99ec0SAndreas Gohr                    echo hsc($v);
19314d99ec0SAndreas Gohr                    echo '</a>';
19414d99ec0SAndreas Gohr                }elseif($k == 'url'){
19554f6c432SAndreas Gohr                    $url = hsc($v);
19654f6c432SAndreas Gohr                    if(strlen($url) > 50){
19754f6c432SAndreas Gohr                        $url = substr($url,0,30).' &hellip; '.substr($url,-20);
19854f6c432SAndreas Gohr                    }
19914d99ec0SAndreas Gohr                    echo '<a href="'.$v.'" class="urlextern">';
20054f6c432SAndreas Gohr                    echo $url;
20114d99ec0SAndreas Gohr                    echo '</a>';
20214d99ec0SAndreas Gohr                }elseif($k == 'html'){
20314d99ec0SAndreas Gohr                    echo $v;
204f5f32cbfSAndreas Gohr                }elseif($k == 'cflag'){
205*95eb68e6SAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/flags/'.hsc($v).'.png" alt="'.hsc($v).'" width="18" height="12"/>';
20614d99ec0SAndreas Gohr                }else{
20714d99ec0SAndreas Gohr                    echo hsc($v);
20814d99ec0SAndreas Gohr                }
20914d99ec0SAndreas Gohr                echo '</td>';
21014d99ec0SAndreas Gohr            }
21114d99ec0SAndreas Gohr            echo '</tr>';
21214d99ec0SAndreas Gohr        }
21314d99ec0SAndreas Gohr        echo '</table>';
2141878f16fSAndreas Gohr    }
2151878f16fSAndreas Gohr
216*95eb68e6SAndreas Gohr    /**
217*95eb68e6SAndreas Gohr     * Create an image
218*95eb68e6SAndreas Gohr     */
219*95eb68e6SAndreas Gohr    function img_build($img){
220*95eb68e6SAndreas Gohr        include(dirname(__FILE__).'/inc/AGC.class.php');
221*95eb68e6SAndreas Gohr
222*95eb68e6SAndreas Gohr        switch($img){
223*95eb68e6SAndreas Gohr            case 'country':
224*95eb68e6SAndreas Gohr                // build top countries + other
225*95eb68e6SAndreas Gohr                $result = $this->sql_countries($this->tlimit,$this->start,0);
226*95eb68e6SAndreas Gohr                $data = array();
227*95eb68e6SAndreas Gohr                $top = 0;
228*95eb68e6SAndreas Gohr                foreach($result as $row){
229*95eb68e6SAndreas Gohr                    if($top < 7){
230*95eb68e6SAndreas Gohr                        $data[$row['country']] = $row['cnt'];
231*95eb68e6SAndreas Gohr                    }else{
232*95eb68e6SAndreas Gohr                        $data['other'] += $row['cnt'];
233*95eb68e6SAndreas Gohr                    }
234*95eb68e6SAndreas Gohr                    $top++;
235*95eb68e6SAndreas Gohr                }
236*95eb68e6SAndreas Gohr                $pie = new AGC(300, 200);
237*95eb68e6SAndreas Gohr                $pie->setProp("showkey",true);
238*95eb68e6SAndreas Gohr                $pie->setProp("showval",false);
239*95eb68e6SAndreas Gohr                $pie->setProp("showgrid",false);
240*95eb68e6SAndreas Gohr                $pie->setProp("type","pie");
241*95eb68e6SAndreas Gohr                $pie->setProp("keyinfo",1);
242*95eb68e6SAndreas Gohr                $pie->setProp("keysize",8);
243*95eb68e6SAndreas Gohr                $pie->setProp("keywidspc",-50);
244*95eb68e6SAndreas Gohr                $pie->setProp("key",array_keys($data));
245*95eb68e6SAndreas Gohr                $pie->addBulkPoints(array_values($data));
246*95eb68e6SAndreas Gohr                @$pie->graph();
247*95eb68e6SAndreas Gohr                $pie->showGraph();
248*95eb68e6SAndreas Gohr                break;
249*95eb68e6SAndreas Gohr            default:
250*95eb68e6SAndreas Gohr                $this->sendGIF();
251*95eb68e6SAndreas Gohr        }
252*95eb68e6SAndreas Gohr    }
253*95eb68e6SAndreas Gohr
254*95eb68e6SAndreas Gohr
255*95eb68e6SAndreas Gohr    function sql_pages($tlimit,$start=0,$limit=20){
256*95eb68e6SAndreas Gohr        $sql = "SELECT page, COUNT(*) as cnt
257*95eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
258*95eb68e6SAndreas Gohr                 WHERE $tlimit
259*95eb68e6SAndreas Gohr                   AND ua_type = 'browser'
260*95eb68e6SAndreas Gohr              GROUP BY page
261*95eb68e6SAndreas Gohr              ORDER BY cnt DESC, page".
262*95eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
263*95eb68e6SAndreas Gohr        return $this->runSQL($sql);
264*95eb68e6SAndreas Gohr    }
265*95eb68e6SAndreas Gohr
266*95eb68e6SAndreas Gohr    function sql_referer($tlimit,$start=0,$limit=20){
267*95eb68e6SAndreas Gohr        $sql = "SELECT ref as url, COUNT(*) as cnt
268*95eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
269*95eb68e6SAndreas Gohr                 WHERE $tlimit
270*95eb68e6SAndreas Gohr                   AND ua_type = 'browser'
271*95eb68e6SAndreas Gohr                   AND ref_type = 'external'
272*95eb68e6SAndreas Gohr              GROUP BY ref_md5
273*95eb68e6SAndreas Gohr              ORDER BY cnt DESC, url".
274*95eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
275*95eb68e6SAndreas Gohr        return $this->runSQL($sql);
276*95eb68e6SAndreas Gohr    }
277*95eb68e6SAndreas Gohr
278*95eb68e6SAndreas Gohr    function sql_countries($tlimit,$start=0,$limit=20){
279*95eb68e6SAndreas Gohr        $sql = "SELECT B.code AS cflag, B.country, COUNT(*) as cnt
280*95eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A,
281*95eb68e6SAndreas Gohr                       ".$this->getConf('db_prefix')."iplocation as B
282*95eb68e6SAndreas Gohr                 WHERE $tlimit
283*95eb68e6SAndreas Gohr                   AND A.ip = B.ip
284*95eb68e6SAndreas Gohr              GROUP BY B.country
285*95eb68e6SAndreas Gohr              ORDER BY cnt DESC, B.country".
286*95eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
287*95eb68e6SAndreas Gohr        return $this->runSQL($sql);
288*95eb68e6SAndreas Gohr    }
289*95eb68e6SAndreas Gohr
290*95eb68e6SAndreas Gohr    /**
291*95eb68e6SAndreas Gohr     * Builds a limit clause
292*95eb68e6SAndreas Gohr     */
293*95eb68e6SAndreas Gohr    function sql_limit($start,$limit){
294*95eb68e6SAndreas Gohr        $start = (int) $start;
295*95eb68e6SAndreas Gohr        $limit = (int) $limit;
296*95eb68e6SAndreas Gohr        if($limit){
297*95eb68e6SAndreas Gohr            return " LIMIT $start,$limit";
298*95eb68e6SAndreas Gohr        }elseif($start){
299*95eb68e6SAndreas Gohr            return " OFFSET $start";
300*95eb68e6SAndreas Gohr        }
301*95eb68e6SAndreas Gohr        return '';
302*95eb68e6SAndreas Gohr    }
3031878f16fSAndreas Gohr
3041878f16fSAndreas Gohr    /**
30514d99ec0SAndreas Gohr     * Return a link to the DB, opening the connection if needed
3061878f16fSAndreas Gohr     */
30714d99ec0SAndreas Gohr    function dbLink(){
3081878f16fSAndreas Gohr        // connect to DB if needed
3091878f16fSAndreas Gohr        if(!$this->dblink){
3101878f16fSAndreas Gohr            $this->dblink = mysql_connect($this->getConf('db_server'),
3111878f16fSAndreas Gohr                                          $this->getConf('db_user'),
3121878f16fSAndreas Gohr                                          $this->getConf('db_password'));
3131878f16fSAndreas Gohr            if(!$this->dblink){
3141878f16fSAndreas Gohr                msg('DB Error: connection failed',-1);
3151878f16fSAndreas Gohr                return null;
3161878f16fSAndreas Gohr            }
3171878f16fSAndreas Gohr            // set utf-8
3181878f16fSAndreas Gohr            if(!mysql_db_query($this->getConf('db_database'),'set names utf8',$this->dblink)){
3191878f16fSAndreas Gohr                msg('DB Error: could not set UTF-8 ('.mysql_error($this->dblink).')',-1);
3201878f16fSAndreas Gohr                return null;
3211878f16fSAndreas Gohr            }
3221878f16fSAndreas Gohr        }
32314d99ec0SAndreas Gohr        return $this->dblink;
32414d99ec0SAndreas Gohr    }
3251878f16fSAndreas Gohr
32614d99ec0SAndreas Gohr    /**
32714d99ec0SAndreas Gohr     * Simple function to run a DB query
32814d99ec0SAndreas Gohr     */
32914d99ec0SAndreas Gohr    function runSQL($sql_string) {
33014d99ec0SAndreas Gohr        $link = $this->dbLink();
33114d99ec0SAndreas Gohr
33214d99ec0SAndreas Gohr        $result = mysql_db_query($this->conf['db_database'],$sql_string,$link);
33394171ff3SAndreas Gohr        if(!$result){
33414d99ec0SAndreas Gohr            msg('DB Error: '.mysql_error($link),-1);
3351878f16fSAndreas Gohr            return null;
3361878f16fSAndreas Gohr        }
3371878f16fSAndreas Gohr
3381878f16fSAndreas Gohr        $resultarray = array();
3391878f16fSAndreas Gohr
3401878f16fSAndreas Gohr        //mysql_db_query returns 1 on a insert statement -> no need to ask for results
3411878f16fSAndreas Gohr        if ($result != 1) {
3421878f16fSAndreas Gohr            for($i=0; $i< mysql_num_rows($result); $i++) {
3431878f16fSAndreas Gohr                $temparray = mysql_fetch_assoc($result);
3441878f16fSAndreas Gohr                $resultarray[]=$temparray;
3451878f16fSAndreas Gohr            }
3461878f16fSAndreas Gohr            mysql_free_result($result);
3471878f16fSAndreas Gohr        }
3481878f16fSAndreas Gohr
34914d99ec0SAndreas Gohr        if (mysql_insert_id($link)) {
35014d99ec0SAndreas Gohr            $resultarray = mysql_insert_id($link); //give back ID on insert
3511878f16fSAndreas Gohr        }
3521878f16fSAndreas Gohr
3531878f16fSAndreas Gohr        return $resultarray;
3541878f16fSAndreas Gohr    }
3551878f16fSAndreas Gohr
3561878f16fSAndreas Gohr    /**
35714d99ec0SAndreas Gohr     * Returns a short name for a User Agent and sets type, version and os info
3581878f16fSAndreas Gohr     */
35914d99ec0SAndreas Gohr    function ua_info($ua,&$type,&$ver,&$os){
36014d99ec0SAndreas Gohr        $ua = strtr($ua,' +','__');
36114d99ec0SAndreas Gohr        $ua = strtolower($ua);
36214d99ec0SAndreas Gohr
36314d99ec0SAndreas Gohr        // common browsers
36414d99ec0SAndreas Gohr        $regvermsie     = '/msie([+_ ]|)([\d\.]*)/i';
36514d99ec0SAndreas Gohr        $regvernetscape = '/netscape.?\/([\d\.]*)/i';
36614d99ec0SAndreas Gohr        $regverfirefox  = '/firefox\/([\d\.]*)/i';
36714d99ec0SAndreas Gohr        $regversvn      = '/svn\/([\d\.]*)/i';
36814d99ec0SAndreas Gohr        $regvermozilla  = '/mozilla(\/|)([\d\.]*)/i';
36914d99ec0SAndreas Gohr        $regnotie       = '/webtv|omniweb|opera/i';
37014d99ec0SAndreas Gohr        $regnotnetscape = '/gecko|compatible|opera|galeon|safari/i';
37114d99ec0SAndreas Gohr
37214d99ec0SAndreas Gohr        $name = '';
37314d99ec0SAndreas Gohr        # IE ?
37414d99ec0SAndreas Gohr        if(preg_match($regvermsie,$ua,$m) && !preg_match($regnotie,$ua)){
37514d99ec0SAndreas Gohr            $type = 'browser';
37614d99ec0SAndreas Gohr            $ver  = $m[2];
37714d99ec0SAndreas Gohr            $name = 'msie';
37814d99ec0SAndreas Gohr        }
37914d99ec0SAndreas Gohr        # Firefox ?
38014d99ec0SAndreas Gohr        elseif (preg_match($regverfirefox,$ua,$m)){
38114d99ec0SAndreas Gohr            $type = 'browser';
38214d99ec0SAndreas Gohr            $ver  = $m[1];
38314d99ec0SAndreas Gohr            $name = 'firefox';
38414d99ec0SAndreas Gohr        }
38514d99ec0SAndreas Gohr        # Subversion ?
38614d99ec0SAndreas Gohr        elseif (preg_match($regversvn,$ua,$m)){
38714d99ec0SAndreas Gohr            $type = 'rcs';
38814d99ec0SAndreas Gohr            $ver  = $m[1];
38914d99ec0SAndreas Gohr            $name = 'svn';
39014d99ec0SAndreas Gohr        }
39114d99ec0SAndreas Gohr        # Netscape 6.x, 7.x ... ?
39214d99ec0SAndreas Gohr        elseif (preg_match($regvernetscape,$ua,$m)){
39314d99ec0SAndreas Gohr            $type = 'browser';
39414d99ec0SAndreas Gohr            $ver  = $m[1];
39514d99ec0SAndreas Gohr            $name = 'netscape';
39614d99ec0SAndreas Gohr        }
39714d99ec0SAndreas Gohr        # Netscape 3.x, 4.x ... ?
39814d99ec0SAndreas Gohr        elseif(preg_match($regvermozilla,$ua,$m) && !preg_match($regnotnetscape,$ua)){
39914d99ec0SAndreas Gohr            $type = 'browser';
40014d99ec0SAndreas Gohr            $ver  = $m[2];
40114d99ec0SAndreas Gohr            $name = 'netscape';
40214d99ec0SAndreas Gohr        }else{
40314d99ec0SAndreas Gohr            include(dirname(__FILE__).'/inc/browsers.php');
40414d99ec0SAndreas Gohr            foreach($BrowsersSearchIDOrder as $regex){
40514d99ec0SAndreas Gohr                if(preg_match('/'.$regex.'/',$ua)){
40614d99ec0SAndreas Gohr                    // it's a browser!
40714d99ec0SAndreas Gohr                    $type = 'browser';
40814d99ec0SAndreas Gohr                    $name = strtolower($regex);
40914d99ec0SAndreas Gohr                    break;
41014d99ec0SAndreas Gohr                }
41114d99ec0SAndreas Gohr            }
41214d99ec0SAndreas Gohr        }
41314d99ec0SAndreas Gohr
41414d99ec0SAndreas Gohr        // check OS for browsers
41514d99ec0SAndreas Gohr        if($type == 'browser'){
41614d99ec0SAndreas Gohr            include(dirname(__FILE__).'/inc/operating_systems.php');
41714d99ec0SAndreas Gohr            foreach($OSSearchIDOrder as $regex){
41814d99ec0SAndreas Gohr                if(preg_match('/'.$regex.'/',$ua)){
41914d99ec0SAndreas Gohr                    $os = $OSHashID[$regex];
42014d99ec0SAndreas Gohr                    break;
42114d99ec0SAndreas Gohr                }
42214d99ec0SAndreas Gohr            }
42314d99ec0SAndreas Gohr
42414d99ec0SAndreas Gohr        }
42514d99ec0SAndreas Gohr
42614d99ec0SAndreas Gohr        // are we done now?
42714d99ec0SAndreas Gohr        if($name) return $name;
42814d99ec0SAndreas Gohr
42914d99ec0SAndreas Gohr        include(dirname(__FILE__).'/inc/robots.php');
43014d99ec0SAndreas Gohr        foreach($RobotsSearchIDOrder as $regex){
43114d99ec0SAndreas Gohr            if(preg_match('/'.$regex.'/',$ua)){
43214d99ec0SAndreas Gohr                    // it's a robot!
43314d99ec0SAndreas Gohr                    $type = 'robot';
43414d99ec0SAndreas Gohr                    return strtolower($regex);
43514d99ec0SAndreas Gohr            }
43614d99ec0SAndreas Gohr        }
43714d99ec0SAndreas Gohr
43814d99ec0SAndreas Gohr        // dunno
4391878f16fSAndreas Gohr        return '';
4401878f16fSAndreas Gohr    }
4411878f16fSAndreas Gohr
4421878f16fSAndreas Gohr    /**
44314d99ec0SAndreas Gohr     *
44414d99ec0SAndreas Gohr     * @fixme: put search engine queries in seperate table here
44514d99ec0SAndreas Gohr     */
44614d99ec0SAndreas Gohr    function log_search($referer,&$type){
44714d99ec0SAndreas Gohr        $referer = strtr($referer,' +','__');
44814d99ec0SAndreas Gohr        $referer = strtolower($referer);
44914d99ec0SAndreas Gohr
45014d99ec0SAndreas Gohr        include(dirname(__FILE__).'/inc/search_engines.php');
45114d99ec0SAndreas Gohr
45214d99ec0SAndreas Gohr        foreach($SearchEnginesSearchIDOrder as $regex){
45314d99ec0SAndreas Gohr            if(preg_match('/'.$regex.'/',$referer)){
45414d99ec0SAndreas Gohr                if(!$NotSearchEnginesKeys[$regex] ||
45514d99ec0SAndreas Gohr                   !preg_match('/'.$NotSearchEnginesKeys[$regex].'/',$referer)){
45614d99ec0SAndreas Gohr                    // it's a search engine!
45714d99ec0SAndreas Gohr                    $type = 'search';
45814d99ec0SAndreas Gohr                    break;
45914d99ec0SAndreas Gohr                }
46014d99ec0SAndreas Gohr            }
46114d99ec0SAndreas Gohr        }
46214d99ec0SAndreas Gohr        if($type != 'search') return; // we're done here
46314d99ec0SAndreas Gohr
46414d99ec0SAndreas Gohr        #fixme now do the keyword magic!
46514d99ec0SAndreas Gohr    }
46614d99ec0SAndreas Gohr
46714d99ec0SAndreas Gohr    /**
46814d99ec0SAndreas Gohr     * Resolve IP to country/city
46914d99ec0SAndreas Gohr     */
47014d99ec0SAndreas Gohr    function log_ip($ip){
47114d99ec0SAndreas Gohr        // check if IP already known and up-to-date
47214d99ec0SAndreas Gohr        $sql = "SELECT ip
47314d99ec0SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."iplocation
47414d99ec0SAndreas Gohr                 WHERE ip ='".addslashes($ip)."'
47514d99ec0SAndreas Gohr                   AND lastupd > DATE_SUB(CURDATE(),INTERVAL 30 DAY)";
47614d99ec0SAndreas Gohr        $result = $this->runSQL($sql);
47714d99ec0SAndreas Gohr        if($result[0]['ip']) return;
47814d99ec0SAndreas Gohr
47914d99ec0SAndreas Gohr        $http = new DokuHTTPClient();
48014d99ec0SAndreas Gohr        $http->timeout = 10;
48114d99ec0SAndreas Gohr        $data = $http->get('http://api.hostip.info/get_html.php?ip='.$ip);
48214d99ec0SAndreas Gohr
48314d99ec0SAndreas Gohr        if(preg_match('/^Country: (.*?) \((.*?)\)\nCity: (.*?)$/s',$data,$match)){
48414d99ec0SAndreas Gohr            $country = addslashes(trim($match[1]));
48514d99ec0SAndreas Gohr            $code    = addslashes(strtolower(trim($match[2])));
48614d99ec0SAndreas Gohr            $city    = addslashes(trim($match[3]));
48714d99ec0SAndreas Gohr            $host    = addslashes(gethostbyaddr($ip));
48814d99ec0SAndreas Gohr            $ip      = addslashes($ip);
48914d99ec0SAndreas Gohr
49014d99ec0SAndreas Gohr            $sql = "REPLACE INTO ".$this->getConf('db_prefix')."iplocation
49114d99ec0SAndreas Gohr                        SET ip = '$ip',
49214d99ec0SAndreas Gohr                            country = '$country',
49314d99ec0SAndreas Gohr                            code    = '$code',
49414d99ec0SAndreas Gohr                            city    = '$city',
49514d99ec0SAndreas Gohr                            host    = '$host'";
49614d99ec0SAndreas Gohr            $this->runSQL($sql);
49714d99ec0SAndreas Gohr        }
49814d99ec0SAndreas Gohr    }
49914d99ec0SAndreas Gohr
50014d99ec0SAndreas Gohr    /**
5011878f16fSAndreas Gohr     * log a page access
5021878f16fSAndreas Gohr     *
5031878f16fSAndreas Gohr     * called from log.php
5041878f16fSAndreas Gohr     */
5051878f16fSAndreas Gohr    function log_access(){
50694171ff3SAndreas Gohr        if(!$_REQUEST['p']) return;
50794171ff3SAndreas Gohr
50814d99ec0SAndreas Gohr        # FIXME check referer against blacklist and drop logging for bad boys
50914d99ec0SAndreas Gohr
51014d99ec0SAndreas Gohr        // handle referer
51114d99ec0SAndreas Gohr        $referer = trim($_REQUEST['r']);
51214d99ec0SAndreas Gohr        if($referer){
51314d99ec0SAndreas Gohr            $ref     = addslashes($referer);
51414d99ec0SAndreas Gohr            $ref_md5 = ($ref) ? md5($referer) : '';
51514d99ec0SAndreas Gohr            if(strpos($referer,DOKU_URL) === 0){
51614d99ec0SAndreas Gohr                $ref_type = 'internal';
51714d99ec0SAndreas Gohr            }else{
51814d99ec0SAndreas Gohr                $ref_type = 'external';
51914d99ec0SAndreas Gohr                $this->log_search($referer,$ref_type);
52014d99ec0SAndreas Gohr            }
52114d99ec0SAndreas Gohr        }else{
52214d99ec0SAndreas Gohr            $ref      = '';
52314d99ec0SAndreas Gohr            $ref_md5  = '';
52414d99ec0SAndreas Gohr            $ref_type = '';
52514d99ec0SAndreas Gohr        }
52614d99ec0SAndreas Gohr
52714d99ec0SAndreas Gohr        // handle user agent
52814d99ec0SAndreas Gohr        $agent   = trim($_SERVER['HTTP_USER_AGENT']);
52914d99ec0SAndreas Gohr
53014d99ec0SAndreas Gohr        $ua      = addslashes($agent);
53114d99ec0SAndreas Gohr        $ua_type = '';
53214d99ec0SAndreas Gohr        $ua_ver  = '';
53314d99ec0SAndreas Gohr        $os      = '';
53414d99ec0SAndreas Gohr        $ua_info = addslashes($this->ua_info($agent,$ua_type,$ua_ver,$os));
53514d99ec0SAndreas Gohr
5361878f16fSAndreas Gohr        $page    = addslashes($_REQUEST['p']);
5371878f16fSAndreas Gohr        $ip      = addslashes($_SERVER['REMOTE_ADDR']);
5381878f16fSAndreas Gohr        $sx      = (int) $_REQUEST['sx'];
5391878f16fSAndreas Gohr        $sy      = (int) $_REQUEST['sy'];
5401878f16fSAndreas Gohr        $vx      = (int) $_REQUEST['vx'];
5411878f16fSAndreas Gohr        $vy      = (int) $_REQUEST['vy'];
5421878f16fSAndreas Gohr        $user    = addslashes($_SERVER['REMOTE_USER']);
5431878f16fSAndreas Gohr        $session = addslashes(session_id());
5441878f16fSAndreas Gohr
54594171ff3SAndreas Gohr        $sql  = "INSERT DELAYED INTO ".$this->getConf('db_prefix')."access
5461878f16fSAndreas Gohr                    SET page     = '$page',
5471878f16fSAndreas Gohr                        ip       = '$ip',
5481878f16fSAndreas Gohr                        ua       = '$ua',
5491878f16fSAndreas Gohr                        ua_info  = '$ua_info',
55014d99ec0SAndreas Gohr                        ua_type  = '$ua_type',
55114d99ec0SAndreas Gohr                        ua_ver   = '$ua_ver',
55214d99ec0SAndreas Gohr                        os       = '$os',
5531878f16fSAndreas Gohr                        ref      = '$ref',
55494171ff3SAndreas Gohr                        ref_md5  = '$ref_md5',
55514d99ec0SAndreas Gohr                        ref_type = '$ref_type',
5561878f16fSAndreas Gohr                        screen_x = '$sx',
5571878f16fSAndreas Gohr                        screen_y = '$sy',
5581878f16fSAndreas Gohr                        view_x   = '$vx',
5591878f16fSAndreas Gohr                        view_y   = '$vy',
5601878f16fSAndreas Gohr                        user     = '$user',
5611878f16fSAndreas Gohr                        session  = '$session'";
5621878f16fSAndreas Gohr        $ok = $this->runSQL($sql);
5631878f16fSAndreas Gohr        if(is_null($ok)){
5641878f16fSAndreas Gohr            global $MSG;
5651878f16fSAndreas Gohr            print_r($MSG);
5661878f16fSAndreas Gohr        }
56714d99ec0SAndreas Gohr
56814d99ec0SAndreas Gohr        // resolve the IP
56914d99ec0SAndreas Gohr        $this->log_ip($_SERVER['REMOTE_ADDR']);
5701878f16fSAndreas Gohr    }
5711878f16fSAndreas Gohr
5721878f16fSAndreas Gohr    /**
5731878f16fSAndreas Gohr     * Just send a 1x1 pixel blank gif to the browser
5741878f16fSAndreas Gohr     *
5751878f16fSAndreas Gohr     * @called from log.php
5761878f16fSAndreas Gohr     *
5771878f16fSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
5781878f16fSAndreas Gohr     * @author Harry Fuecks <fuecks@gmail.com>
5791878f16fSAndreas Gohr     */
5801878f16fSAndreas Gohr    function sendGIF(){
5811878f16fSAndreas Gohr        $img = base64_decode('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7');
5821878f16fSAndreas Gohr        header('Content-Type: image/gif');
5831878f16fSAndreas Gohr        header('Content-Length: '.strlen($img));
5841878f16fSAndreas Gohr        header('Connection: Close');
5851878f16fSAndreas Gohr        print $img;
5861878f16fSAndreas Gohr        flush();
5871878f16fSAndreas Gohr        // Browser should drop connection after this
5881878f16fSAndreas Gohr        // Thinks it's got the whole image
5891878f16fSAndreas Gohr    }
5901878f16fSAndreas Gohr
5911878f16fSAndreas Gohr}
592