xref: /plugin/statistics/admin.php (revision 9da6395d738943db132258012a01609b922e0afa)
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     = '';
2495eb68e6SAndreas 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']);
5395eb68e6SAndreas Gohr
5495eb68e6SAndreas Gohr        $this->start = (int) $_REQUEST['s'];
5595eb68e6SAndreas 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() {
74*9da6395dSAndreas Gohr        $this->html_toc();
75264f1744SAndreas Gohr        echo '<h1>Access Statistics</h1>';
76264f1744SAndreas Gohr        $this->html_timeselect();
77264f1744SAndreas Gohr
78264f1744SAndreas Gohr        switch($this->opt){
79*9da6395dSAndreas Gohr            case 'country':
80*9da6395dSAndreas Gohr                $this->html_country();
81*9da6395dSAndreas Gohr                break;
82*9da6395dSAndreas Gohr            case 'page':
83*9da6395dSAndreas Gohr                $this->html_page();
84*9da6395dSAndreas Gohr                break;
85*9da6395dSAndreas Gohr            case 'referer':
86*9da6395dSAndreas Gohr                $this->html_referer();
87*9da6395dSAndreas Gohr                break;
8814d99ec0SAndreas Gohr            default:
89*9da6395dSAndreas Gohr                $this->html_dashboard();
9014d99ec0SAndreas Gohr        }
9114d99ec0SAndreas Gohr    }
9214d99ec0SAndreas Gohr
93*9da6395dSAndreas Gohr    function html_toc(){
94*9da6395dSAndreas Gohr        echo '<div class="toc">';
95*9da6395dSAndreas Gohr        echo '<div class="tocheader toctoggle" id="toc__header">';
96*9da6395dSAndreas Gohr        echo 'Detailed Statistics';
97*9da6395dSAndreas Gohr        echo '</div>';
98*9da6395dSAndreas Gohr        echo '<div id="toc__inside">';
99*9da6395dSAndreas Gohr        echo '<ul class="toc">';
100*9da6395dSAndreas Gohr
101*9da6395dSAndreas Gohr        echo '<li><div class="li">';
102*9da6395dSAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=&amp;f='.$this->from.'&amp;t='.$this->to.'&amp;s='.$this->start.'">Dashboard</a>';
103*9da6395dSAndreas Gohr        echo '</div></li>';
104*9da6395dSAndreas Gohr
105*9da6395dSAndreas Gohr        echo '<li><div class="li">';
106*9da6395dSAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=page&amp;f='.$this->from.'&amp;t='.$this->to.'&amp;s='.$this->start.'">Pages</a>';
107*9da6395dSAndreas Gohr        echo '</div></li>';
108*9da6395dSAndreas Gohr
109*9da6395dSAndreas Gohr        echo '<li><div class="li">';
110*9da6395dSAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=referer&amp;f='.$this->from.'&amp;t='.$this->to.'&amp;s='.$this->start.'">Incoming Links</a>';
111*9da6395dSAndreas Gohr        echo '</div></li>';
112*9da6395dSAndreas Gohr
113*9da6395dSAndreas Gohr        echo '<li><div class="li">';
114*9da6395dSAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=country&amp;f='.$this->from.'&amp;t='.$this->to.'&amp;s='.$this->start.'">Countries</a>';
115*9da6395dSAndreas Gohr        echo '</div></li>';
116*9da6395dSAndreas Gohr
117*9da6395dSAndreas Gohr        echo '</ul>';
118*9da6395dSAndreas Gohr        echo '</div>';
119*9da6395dSAndreas Gohr        echo '</div>';
120*9da6395dSAndreas Gohr    }
121*9da6395dSAndreas Gohr
122264f1744SAndreas Gohr    /**
123264f1744SAndreas Gohr     * Print the time selection menu
124264f1744SAndreas Gohr     */
12514d99ec0SAndreas Gohr    function html_timeselect(){
126264f1744SAndreas Gohr        $now   = date('Y-m-d');
127264f1744SAndreas Gohr        $yday  = date('Y-m-d',time()-(60*60*24));
128264f1744SAndreas Gohr        $week  = date('Y-m-d',time()-(60*60*24*7));
129264f1744SAndreas Gohr        $month = date('Y-m-d',time()-(60*60*24*30));
13014d99ec0SAndreas Gohr
131264f1744SAndreas Gohr        echo '<div class="plg_stats_timeselect">';
132264f1744SAndreas Gohr        echo '<span>Select the timeframe:</span>';
133264f1744SAndreas Gohr        echo '<ul>';
134264f1744SAndreas Gohr
135264f1744SAndreas Gohr        echo '<li>';
13695eb68e6SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$now.'&amp;t='.$now.'&amp;s='.$this->start.'">';
137264f1744SAndreas Gohr        echo 'today';
138264f1744SAndreas Gohr        echo '</a>';
139264f1744SAndreas Gohr        echo '</li>';
140264f1744SAndreas Gohr
141264f1744SAndreas Gohr        echo '<li>';
14295eb68e6SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$yday.'&amp;t='.$yday.'&amp;s='.$this->start.'">';
143264f1744SAndreas Gohr        echo 'yesterday';
144264f1744SAndreas Gohr        echo '</a>';
145264f1744SAndreas Gohr        echo '</li>';
146264f1744SAndreas Gohr
147264f1744SAndreas Gohr        echo '<li>';
14895eb68e6SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$week.'&amp;t='.$now.'&amp;s='.$this->start.'">';
149264f1744SAndreas Gohr        echo 'last 7 days';
150264f1744SAndreas Gohr        echo '</a>';
151264f1744SAndreas Gohr        echo '</li>';
152264f1744SAndreas Gohr
153264f1744SAndreas Gohr        echo '<li>';
15495eb68e6SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$month.'&amp;t='.$now.'&amp;s='.$this->start.'">';
155264f1744SAndreas Gohr        echo 'last 30 days';
156264f1744SAndreas Gohr        echo '</a>';
157264f1744SAndreas Gohr        echo '</li>';
158264f1744SAndreas Gohr
159264f1744SAndreas Gohr        echo '</ul>';
160264f1744SAndreas Gohr
161264f1744SAndreas Gohr
162264f1744SAndreas Gohr        echo '<form action="" method="get">';
163264f1744SAndreas Gohr        echo '<input type="hidden" name="do" value="admin" />';
164264f1744SAndreas Gohr        echo '<input type="hidden" name="page" value="statistics" />';
165264f1744SAndreas Gohr        echo '<input type="hidden" name="opt" value="'.$this->opt.'" />';
16695eb68e6SAndreas Gohr        echo '<input type="hidden" name="s" value="'.$this->start.'" />';
167264f1744SAndreas Gohr        echo '<input type="text" name="f" value="'.$this->from.'" class="edit" />';
168264f1744SAndreas Gohr        echo '<input type="text" name="t" value="'.$this->to.'" class="edit" />';
169264f1744SAndreas Gohr        echo '<input type="submit" value="go" class="button" />';
17014d99ec0SAndreas Gohr        echo '</form>';
171264f1744SAndreas Gohr
172264f1744SAndreas Gohr        echo '</div>';
17314d99ec0SAndreas Gohr    }
17414d99ec0SAndreas Gohr
17514d99ec0SAndreas Gohr
176f5f32cbfSAndreas Gohr    /**
177f5f32cbfSAndreas Gohr     * Print an introductionary screen
178f5f32cbfSAndreas Gohr     */
17914d99ec0SAndreas Gohr    function html_dashboard(){
180264f1744SAndreas Gohr        echo '<div class="plg_stats_dashboard">';
181264f1744SAndreas Gohr
18214d99ec0SAndreas Gohr
18387d5e44bSAndreas Gohr        // top pages today
184264f1744SAndreas Gohr        echo '<div>';
185264f1744SAndreas Gohr        echo '<h2>Most popular pages</h2>';
18695eb68e6SAndreas Gohr        $result = $this->sql_pages($this->tlimit,$this->start,15);
18787d5e44bSAndreas Gohr        $this->html_resulttable($result,array('Pages','Count'));
188264f1744SAndreas Gohr        echo '</div>';
18987d5e44bSAndreas Gohr
19087d5e44bSAndreas Gohr        // top referer today
191264f1744SAndreas Gohr        echo '<div>';
192264f1744SAndreas Gohr        echo '<h2>Top incoming links</h2>';
19395eb68e6SAndreas Gohr        $result = $this->sql_referer($this->tlimit,$this->start,15);
19487d5e44bSAndreas Gohr        $this->html_resulttable($result,array('Incoming Links','Count'));
195264f1744SAndreas Gohr        echo '</div>';
19654f6c432SAndreas Gohr
19754f6c432SAndreas Gohr        // top countries today
198264f1744SAndreas Gohr        echo '<div>';
199264f1744SAndreas Gohr        echo '<h2>Visitor\'s top countries</h2>';
20095eb68e6SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=country&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
20195eb68e6SAndreas Gohr//        $result = $this->sql_countries($this->tlimit,$this->start,15);
20295eb68e6SAndreas Gohr//        $this->html_resulttable($result,array('','Countries','Count'));
203264f1744SAndreas Gohr        echo '</div>';
204264f1744SAndreas Gohr
205264f1744SAndreas Gohr        echo '</div>';
20614d99ec0SAndreas Gohr    }
20714d99ec0SAndreas Gohr
208*9da6395dSAndreas Gohr    function html_country(){
209*9da6395dSAndreas Gohr        echo '<div class="plg_stats_full">';
210*9da6395dSAndreas Gohr        echo '<h2>Visitor\'s Countries</h2>';
211*9da6395dSAndreas Gohr        $result = $this->sql_countries($this->tlimit,$this->start,150);
212*9da6395dSAndreas Gohr        $this->html_resulttable($result,array('','Countries','Count'));
213*9da6395dSAndreas Gohr        echo '</div>';
214*9da6395dSAndreas Gohr    }
215*9da6395dSAndreas Gohr
216*9da6395dSAndreas Gohr    function html_page(){
217*9da6395dSAndreas Gohr        echo '<div class="plg_stats_full">';
218*9da6395dSAndreas Gohr        echo '<h2>Popular Pages</h2>';
219*9da6395dSAndreas Gohr        $result = $this->sql_pages($this->tlimit,$this->start,150);
220*9da6395dSAndreas Gohr        $this->html_resulttable($result,array('Page','Count'));
221*9da6395dSAndreas Gohr        echo '</div>';
222*9da6395dSAndreas Gohr    }
223*9da6395dSAndreas Gohr
224*9da6395dSAndreas Gohr    function html_referer(){
225*9da6395dSAndreas Gohr        echo '<div class="plg_stats_full">';
226*9da6395dSAndreas Gohr        echo '<h2>Incoming Links</h2>';
227*9da6395dSAndreas Gohr        $result = $this->sql_referer($this->tlimit,$this->start,150);
228*9da6395dSAndreas Gohr        $this->html_resulttable($result,array('Incoming Link','Count'));
229*9da6395dSAndreas Gohr        echo '</div>';
230*9da6395dSAndreas Gohr    }
231*9da6395dSAndreas Gohr
232*9da6395dSAndreas Gohr
233*9da6395dSAndreas Gohr
23414d99ec0SAndreas Gohr    /**
23514d99ec0SAndreas Gohr     * Display a result in a HTML table
23614d99ec0SAndreas Gohr     */
23714d99ec0SAndreas Gohr    function html_resulttable($result,$header){
23814d99ec0SAndreas Gohr        echo '<table>';
23914d99ec0SAndreas Gohr        echo '<tr>';
24014d99ec0SAndreas Gohr        foreach($header as $h){
24114d99ec0SAndreas Gohr            echo '<th>'.hsc($h).'</th>';
24214d99ec0SAndreas Gohr        }
24314d99ec0SAndreas Gohr        echo '</tr>';
24414d99ec0SAndreas Gohr
24514d99ec0SAndreas Gohr        foreach($result as $row){
24614d99ec0SAndreas Gohr            echo '<tr>';
24714d99ec0SAndreas Gohr            foreach($row as $k => $v){
24814d99ec0SAndreas Gohr                echo '<td class="stats_'.$k.'">';
24914d99ec0SAndreas Gohr                if($k == 'page'){
25014d99ec0SAndreas Gohr                    echo '<a href="'.wl($v).'" class="wikilink1">';
25114d99ec0SAndreas Gohr                    echo hsc($v);
25214d99ec0SAndreas Gohr                    echo '</a>';
25314d99ec0SAndreas Gohr                }elseif($k == 'url'){
25454f6c432SAndreas Gohr                    $url = hsc($v);
25554f6c432SAndreas Gohr                    if(strlen($url) > 50){
25654f6c432SAndreas Gohr                        $url = substr($url,0,30).' &hellip; '.substr($url,-20);
25754f6c432SAndreas Gohr                    }
25814d99ec0SAndreas Gohr                    echo '<a href="'.$v.'" class="urlextern">';
25954f6c432SAndreas Gohr                    echo $url;
26014d99ec0SAndreas Gohr                    echo '</a>';
26114d99ec0SAndreas Gohr                }elseif($k == 'html'){
26214d99ec0SAndreas Gohr                    echo $v;
263f5f32cbfSAndreas Gohr                }elseif($k == 'cflag'){
26495eb68e6SAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/flags/'.hsc($v).'.png" alt="'.hsc($v).'" width="18" height="12"/>';
26514d99ec0SAndreas Gohr                }else{
26614d99ec0SAndreas Gohr                    echo hsc($v);
26714d99ec0SAndreas Gohr                }
26814d99ec0SAndreas Gohr                echo '</td>';
26914d99ec0SAndreas Gohr            }
27014d99ec0SAndreas Gohr            echo '</tr>';
27114d99ec0SAndreas Gohr        }
27214d99ec0SAndreas Gohr        echo '</table>';
2731878f16fSAndreas Gohr    }
2741878f16fSAndreas Gohr
27595eb68e6SAndreas Gohr    /**
27695eb68e6SAndreas Gohr     * Create an image
27795eb68e6SAndreas Gohr     */
27895eb68e6SAndreas Gohr    function img_build($img){
27995eb68e6SAndreas Gohr        include(dirname(__FILE__).'/inc/AGC.class.php');
28095eb68e6SAndreas Gohr
28195eb68e6SAndreas Gohr        switch($img){
28295eb68e6SAndreas Gohr            case 'country':
28395eb68e6SAndreas Gohr                // build top countries + other
28495eb68e6SAndreas Gohr                $result = $this->sql_countries($this->tlimit,$this->start,0);
28595eb68e6SAndreas Gohr                $data = array();
28695eb68e6SAndreas Gohr                $top = 0;
28795eb68e6SAndreas Gohr                foreach($result as $row){
28895eb68e6SAndreas Gohr                    if($top < 7){
28995eb68e6SAndreas Gohr                        $data[$row['country']] = $row['cnt'];
29095eb68e6SAndreas Gohr                    }else{
29195eb68e6SAndreas Gohr                        $data['other'] += $row['cnt'];
29295eb68e6SAndreas Gohr                    }
29395eb68e6SAndreas Gohr                    $top++;
29495eb68e6SAndreas Gohr                }
29595eb68e6SAndreas Gohr                $pie = new AGC(300, 200);
29695eb68e6SAndreas Gohr                $pie->setProp("showkey",true);
29795eb68e6SAndreas Gohr                $pie->setProp("showval",false);
29895eb68e6SAndreas Gohr                $pie->setProp("showgrid",false);
29995eb68e6SAndreas Gohr                $pie->setProp("type","pie");
30095eb68e6SAndreas Gohr                $pie->setProp("keyinfo",1);
30195eb68e6SAndreas Gohr                $pie->setProp("keysize",8);
30295eb68e6SAndreas Gohr                $pie->setProp("keywidspc",-50);
30395eb68e6SAndreas Gohr                $pie->setProp("key",array_keys($data));
30495eb68e6SAndreas Gohr                $pie->addBulkPoints(array_values($data));
30595eb68e6SAndreas Gohr                @$pie->graph();
30695eb68e6SAndreas Gohr                $pie->showGraph();
30795eb68e6SAndreas Gohr                break;
30895eb68e6SAndreas Gohr            default:
30995eb68e6SAndreas Gohr                $this->sendGIF();
31095eb68e6SAndreas Gohr        }
31195eb68e6SAndreas Gohr    }
31295eb68e6SAndreas Gohr
31395eb68e6SAndreas Gohr
31495eb68e6SAndreas Gohr    function sql_pages($tlimit,$start=0,$limit=20){
31595eb68e6SAndreas Gohr        $sql = "SELECT page, COUNT(*) as cnt
31695eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
31795eb68e6SAndreas Gohr                 WHERE $tlimit
31895eb68e6SAndreas Gohr                   AND ua_type = 'browser'
31995eb68e6SAndreas Gohr              GROUP BY page
32095eb68e6SAndreas Gohr              ORDER BY cnt DESC, page".
32195eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
32295eb68e6SAndreas Gohr        return $this->runSQL($sql);
32395eb68e6SAndreas Gohr    }
32495eb68e6SAndreas Gohr
32595eb68e6SAndreas Gohr    function sql_referer($tlimit,$start=0,$limit=20){
32695eb68e6SAndreas Gohr        $sql = "SELECT ref as url, COUNT(*) as cnt
32795eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
32895eb68e6SAndreas Gohr                 WHERE $tlimit
32995eb68e6SAndreas Gohr                   AND ua_type = 'browser'
33095eb68e6SAndreas Gohr                   AND ref_type = 'external'
33195eb68e6SAndreas Gohr              GROUP BY ref_md5
33295eb68e6SAndreas Gohr              ORDER BY cnt DESC, url".
33395eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
33495eb68e6SAndreas Gohr        return $this->runSQL($sql);
33595eb68e6SAndreas Gohr    }
33695eb68e6SAndreas Gohr
33795eb68e6SAndreas Gohr    function sql_countries($tlimit,$start=0,$limit=20){
33895eb68e6SAndreas Gohr        $sql = "SELECT B.code AS cflag, B.country, COUNT(*) as cnt
33995eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A,
34095eb68e6SAndreas Gohr                       ".$this->getConf('db_prefix')."iplocation as B
34195eb68e6SAndreas Gohr                 WHERE $tlimit
34295eb68e6SAndreas Gohr                   AND A.ip = B.ip
34395eb68e6SAndreas Gohr              GROUP BY B.country
34495eb68e6SAndreas Gohr              ORDER BY cnt DESC, B.country".
34595eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
34695eb68e6SAndreas Gohr        return $this->runSQL($sql);
34795eb68e6SAndreas Gohr    }
34895eb68e6SAndreas Gohr
34995eb68e6SAndreas Gohr    /**
35095eb68e6SAndreas Gohr     * Builds a limit clause
35195eb68e6SAndreas Gohr     */
35295eb68e6SAndreas Gohr    function sql_limit($start,$limit){
35395eb68e6SAndreas Gohr        $start = (int) $start;
35495eb68e6SAndreas Gohr        $limit = (int) $limit;
35595eb68e6SAndreas Gohr        if($limit){
35695eb68e6SAndreas Gohr            return " LIMIT $start,$limit";
35795eb68e6SAndreas Gohr        }elseif($start){
35895eb68e6SAndreas Gohr            return " OFFSET $start";
35995eb68e6SAndreas Gohr        }
36095eb68e6SAndreas Gohr        return '';
36195eb68e6SAndreas Gohr    }
3621878f16fSAndreas Gohr
3631878f16fSAndreas Gohr    /**
36414d99ec0SAndreas Gohr     * Return a link to the DB, opening the connection if needed
3651878f16fSAndreas Gohr     */
36614d99ec0SAndreas Gohr    function dbLink(){
3671878f16fSAndreas Gohr        // connect to DB if needed
3681878f16fSAndreas Gohr        if(!$this->dblink){
3691878f16fSAndreas Gohr            $this->dblink = mysql_connect($this->getConf('db_server'),
3701878f16fSAndreas Gohr                                          $this->getConf('db_user'),
3711878f16fSAndreas Gohr                                          $this->getConf('db_password'));
3721878f16fSAndreas Gohr            if(!$this->dblink){
3731878f16fSAndreas Gohr                msg('DB Error: connection failed',-1);
3741878f16fSAndreas Gohr                return null;
3751878f16fSAndreas Gohr            }
3761878f16fSAndreas Gohr            // set utf-8
3771878f16fSAndreas Gohr            if(!mysql_db_query($this->getConf('db_database'),'set names utf8',$this->dblink)){
3781878f16fSAndreas Gohr                msg('DB Error: could not set UTF-8 ('.mysql_error($this->dblink).')',-1);
3791878f16fSAndreas Gohr                return null;
3801878f16fSAndreas Gohr            }
3811878f16fSAndreas Gohr        }
38214d99ec0SAndreas Gohr        return $this->dblink;
38314d99ec0SAndreas Gohr    }
3841878f16fSAndreas Gohr
38514d99ec0SAndreas Gohr    /**
38614d99ec0SAndreas Gohr     * Simple function to run a DB query
38714d99ec0SAndreas Gohr     */
38814d99ec0SAndreas Gohr    function runSQL($sql_string) {
38914d99ec0SAndreas Gohr        $link = $this->dbLink();
39014d99ec0SAndreas Gohr
39114d99ec0SAndreas Gohr        $result = mysql_db_query($this->conf['db_database'],$sql_string,$link);
39294171ff3SAndreas Gohr        if(!$result){
39314d99ec0SAndreas Gohr            msg('DB Error: '.mysql_error($link),-1);
3941878f16fSAndreas Gohr            return null;
3951878f16fSAndreas Gohr        }
3961878f16fSAndreas Gohr
3971878f16fSAndreas Gohr        $resultarray = array();
3981878f16fSAndreas Gohr
3991878f16fSAndreas Gohr        //mysql_db_query returns 1 on a insert statement -> no need to ask for results
4001878f16fSAndreas Gohr        if ($result != 1) {
4011878f16fSAndreas Gohr            for($i=0; $i< mysql_num_rows($result); $i++) {
4021878f16fSAndreas Gohr                $temparray = mysql_fetch_assoc($result);
4031878f16fSAndreas Gohr                $resultarray[]=$temparray;
4041878f16fSAndreas Gohr            }
4051878f16fSAndreas Gohr            mysql_free_result($result);
4061878f16fSAndreas Gohr        }
4071878f16fSAndreas Gohr
40814d99ec0SAndreas Gohr        if (mysql_insert_id($link)) {
40914d99ec0SAndreas Gohr            $resultarray = mysql_insert_id($link); //give back ID on insert
4101878f16fSAndreas Gohr        }
4111878f16fSAndreas Gohr
4121878f16fSAndreas Gohr        return $resultarray;
4131878f16fSAndreas Gohr    }
4141878f16fSAndreas Gohr
4151878f16fSAndreas Gohr    /**
41614d99ec0SAndreas Gohr     * Returns a short name for a User Agent and sets type, version and os info
4171878f16fSAndreas Gohr     */
41814d99ec0SAndreas Gohr    function ua_info($ua,&$type,&$ver,&$os){
41914d99ec0SAndreas Gohr        $ua = strtr($ua,' +','__');
42014d99ec0SAndreas Gohr        $ua = strtolower($ua);
42114d99ec0SAndreas Gohr
42214d99ec0SAndreas Gohr        // common browsers
42314d99ec0SAndreas Gohr        $regvermsie     = '/msie([+_ ]|)([\d\.]*)/i';
42414d99ec0SAndreas Gohr        $regvernetscape = '/netscape.?\/([\d\.]*)/i';
42514d99ec0SAndreas Gohr        $regverfirefox  = '/firefox\/([\d\.]*)/i';
42614d99ec0SAndreas Gohr        $regversvn      = '/svn\/([\d\.]*)/i';
42714d99ec0SAndreas Gohr        $regvermozilla  = '/mozilla(\/|)([\d\.]*)/i';
42814d99ec0SAndreas Gohr        $regnotie       = '/webtv|omniweb|opera/i';
42914d99ec0SAndreas Gohr        $regnotnetscape = '/gecko|compatible|opera|galeon|safari/i';
43014d99ec0SAndreas Gohr
43114d99ec0SAndreas Gohr        $name = '';
43214d99ec0SAndreas Gohr        # IE ?
43314d99ec0SAndreas Gohr        if(preg_match($regvermsie,$ua,$m) && !preg_match($regnotie,$ua)){
43414d99ec0SAndreas Gohr            $type = 'browser';
43514d99ec0SAndreas Gohr            $ver  = $m[2];
43614d99ec0SAndreas Gohr            $name = 'msie';
43714d99ec0SAndreas Gohr        }
43814d99ec0SAndreas Gohr        # Firefox ?
43914d99ec0SAndreas Gohr        elseif (preg_match($regverfirefox,$ua,$m)){
44014d99ec0SAndreas Gohr            $type = 'browser';
44114d99ec0SAndreas Gohr            $ver  = $m[1];
44214d99ec0SAndreas Gohr            $name = 'firefox';
44314d99ec0SAndreas Gohr        }
44414d99ec0SAndreas Gohr        # Subversion ?
44514d99ec0SAndreas Gohr        elseif (preg_match($regversvn,$ua,$m)){
44614d99ec0SAndreas Gohr            $type = 'rcs';
44714d99ec0SAndreas Gohr            $ver  = $m[1];
44814d99ec0SAndreas Gohr            $name = 'svn';
44914d99ec0SAndreas Gohr        }
45014d99ec0SAndreas Gohr        # Netscape 6.x, 7.x ... ?
45114d99ec0SAndreas Gohr        elseif (preg_match($regvernetscape,$ua,$m)){
45214d99ec0SAndreas Gohr            $type = 'browser';
45314d99ec0SAndreas Gohr            $ver  = $m[1];
45414d99ec0SAndreas Gohr            $name = 'netscape';
45514d99ec0SAndreas Gohr        }
45614d99ec0SAndreas Gohr        # Netscape 3.x, 4.x ... ?
45714d99ec0SAndreas Gohr        elseif(preg_match($regvermozilla,$ua,$m) && !preg_match($regnotnetscape,$ua)){
45814d99ec0SAndreas Gohr            $type = 'browser';
45914d99ec0SAndreas Gohr            $ver  = $m[2];
46014d99ec0SAndreas Gohr            $name = 'netscape';
46114d99ec0SAndreas Gohr        }else{
46214d99ec0SAndreas Gohr            include(dirname(__FILE__).'/inc/browsers.php');
46314d99ec0SAndreas Gohr            foreach($BrowsersSearchIDOrder as $regex){
46414d99ec0SAndreas Gohr                if(preg_match('/'.$regex.'/',$ua)){
46514d99ec0SAndreas Gohr                    // it's a browser!
46614d99ec0SAndreas Gohr                    $type = 'browser';
46714d99ec0SAndreas Gohr                    $name = strtolower($regex);
46814d99ec0SAndreas Gohr                    break;
46914d99ec0SAndreas Gohr                }
47014d99ec0SAndreas Gohr            }
47114d99ec0SAndreas Gohr        }
47214d99ec0SAndreas Gohr
47314d99ec0SAndreas Gohr        // check OS for browsers
47414d99ec0SAndreas Gohr        if($type == 'browser'){
47514d99ec0SAndreas Gohr            include(dirname(__FILE__).'/inc/operating_systems.php');
47614d99ec0SAndreas Gohr            foreach($OSSearchIDOrder as $regex){
47714d99ec0SAndreas Gohr                if(preg_match('/'.$regex.'/',$ua)){
47814d99ec0SAndreas Gohr                    $os = $OSHashID[$regex];
47914d99ec0SAndreas Gohr                    break;
48014d99ec0SAndreas Gohr                }
48114d99ec0SAndreas Gohr            }
48214d99ec0SAndreas Gohr
48314d99ec0SAndreas Gohr        }
48414d99ec0SAndreas Gohr
48514d99ec0SAndreas Gohr        // are we done now?
48614d99ec0SAndreas Gohr        if($name) return $name;
48714d99ec0SAndreas Gohr
48814d99ec0SAndreas Gohr        include(dirname(__FILE__).'/inc/robots.php');
48914d99ec0SAndreas Gohr        foreach($RobotsSearchIDOrder as $regex){
49014d99ec0SAndreas Gohr            if(preg_match('/'.$regex.'/',$ua)){
49114d99ec0SAndreas Gohr                    // it's a robot!
49214d99ec0SAndreas Gohr                    $type = 'robot';
49314d99ec0SAndreas Gohr                    return strtolower($regex);
49414d99ec0SAndreas Gohr            }
49514d99ec0SAndreas Gohr        }
49614d99ec0SAndreas Gohr
49714d99ec0SAndreas Gohr        // dunno
4981878f16fSAndreas Gohr        return '';
4991878f16fSAndreas Gohr    }
5001878f16fSAndreas Gohr
5011878f16fSAndreas Gohr    /**
50214d99ec0SAndreas Gohr     *
50314d99ec0SAndreas Gohr     * @fixme: put search engine queries in seperate table here
50414d99ec0SAndreas Gohr     */
50514d99ec0SAndreas Gohr    function log_search($referer,&$type){
50614d99ec0SAndreas Gohr        $referer = strtr($referer,' +','__');
50714d99ec0SAndreas Gohr        $referer = strtolower($referer);
50814d99ec0SAndreas Gohr
50914d99ec0SAndreas Gohr        include(dirname(__FILE__).'/inc/search_engines.php');
51014d99ec0SAndreas Gohr
51114d99ec0SAndreas Gohr        foreach($SearchEnginesSearchIDOrder as $regex){
51214d99ec0SAndreas Gohr            if(preg_match('/'.$regex.'/',$referer)){
51314d99ec0SAndreas Gohr                if(!$NotSearchEnginesKeys[$regex] ||
51414d99ec0SAndreas Gohr                   !preg_match('/'.$NotSearchEnginesKeys[$regex].'/',$referer)){
51514d99ec0SAndreas Gohr                    // it's a search engine!
51614d99ec0SAndreas Gohr                    $type = 'search';
51714d99ec0SAndreas Gohr                    break;
51814d99ec0SAndreas Gohr                }
51914d99ec0SAndreas Gohr            }
52014d99ec0SAndreas Gohr        }
52114d99ec0SAndreas Gohr        if($type != 'search') return; // we're done here
52214d99ec0SAndreas Gohr
52314d99ec0SAndreas Gohr        #fixme now do the keyword magic!
52414d99ec0SAndreas Gohr    }
52514d99ec0SAndreas Gohr
52614d99ec0SAndreas Gohr    /**
52714d99ec0SAndreas Gohr     * Resolve IP to country/city
52814d99ec0SAndreas Gohr     */
52914d99ec0SAndreas Gohr    function log_ip($ip){
53014d99ec0SAndreas Gohr        // check if IP already known and up-to-date
53114d99ec0SAndreas Gohr        $sql = "SELECT ip
53214d99ec0SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."iplocation
53314d99ec0SAndreas Gohr                 WHERE ip ='".addslashes($ip)."'
53414d99ec0SAndreas Gohr                   AND lastupd > DATE_SUB(CURDATE(),INTERVAL 30 DAY)";
53514d99ec0SAndreas Gohr        $result = $this->runSQL($sql);
53614d99ec0SAndreas Gohr        if($result[0]['ip']) return;
53714d99ec0SAndreas Gohr
53814d99ec0SAndreas Gohr        $http = new DokuHTTPClient();
53914d99ec0SAndreas Gohr        $http->timeout = 10;
54014d99ec0SAndreas Gohr        $data = $http->get('http://api.hostip.info/get_html.php?ip='.$ip);
54114d99ec0SAndreas Gohr
54214d99ec0SAndreas Gohr        if(preg_match('/^Country: (.*?) \((.*?)\)\nCity: (.*?)$/s',$data,$match)){
54314d99ec0SAndreas Gohr            $country = addslashes(trim($match[1]));
54414d99ec0SAndreas Gohr            $code    = addslashes(strtolower(trim($match[2])));
54514d99ec0SAndreas Gohr            $city    = addslashes(trim($match[3]));
54614d99ec0SAndreas Gohr            $host    = addslashes(gethostbyaddr($ip));
54714d99ec0SAndreas Gohr            $ip      = addslashes($ip);
54814d99ec0SAndreas Gohr
54914d99ec0SAndreas Gohr            $sql = "REPLACE INTO ".$this->getConf('db_prefix')."iplocation
55014d99ec0SAndreas Gohr                        SET ip = '$ip',
55114d99ec0SAndreas Gohr                            country = '$country',
55214d99ec0SAndreas Gohr                            code    = '$code',
55314d99ec0SAndreas Gohr                            city    = '$city',
55414d99ec0SAndreas Gohr                            host    = '$host'";
55514d99ec0SAndreas Gohr            $this->runSQL($sql);
55614d99ec0SAndreas Gohr        }
55714d99ec0SAndreas Gohr    }
55814d99ec0SAndreas Gohr
55914d99ec0SAndreas Gohr    /**
5601878f16fSAndreas Gohr     * log a page access
5611878f16fSAndreas Gohr     *
5621878f16fSAndreas Gohr     * called from log.php
5631878f16fSAndreas Gohr     */
5641878f16fSAndreas Gohr    function log_access(){
56594171ff3SAndreas Gohr        if(!$_REQUEST['p']) return;
56694171ff3SAndreas Gohr
56714d99ec0SAndreas Gohr        # FIXME check referer against blacklist and drop logging for bad boys
56814d99ec0SAndreas Gohr
56914d99ec0SAndreas Gohr        // handle referer
57014d99ec0SAndreas Gohr        $referer = trim($_REQUEST['r']);
57114d99ec0SAndreas Gohr        if($referer){
57214d99ec0SAndreas Gohr            $ref     = addslashes($referer);
57314d99ec0SAndreas Gohr            $ref_md5 = ($ref) ? md5($referer) : '';
57414d99ec0SAndreas Gohr            if(strpos($referer,DOKU_URL) === 0){
57514d99ec0SAndreas Gohr                $ref_type = 'internal';
57614d99ec0SAndreas Gohr            }else{
57714d99ec0SAndreas Gohr                $ref_type = 'external';
57814d99ec0SAndreas Gohr                $this->log_search($referer,$ref_type);
57914d99ec0SAndreas Gohr            }
58014d99ec0SAndreas Gohr        }else{
58114d99ec0SAndreas Gohr            $ref      = '';
58214d99ec0SAndreas Gohr            $ref_md5  = '';
58314d99ec0SAndreas Gohr            $ref_type = '';
58414d99ec0SAndreas Gohr        }
58514d99ec0SAndreas Gohr
58614d99ec0SAndreas Gohr        // handle user agent
58714d99ec0SAndreas Gohr        $agent   = trim($_SERVER['HTTP_USER_AGENT']);
58814d99ec0SAndreas Gohr
58914d99ec0SAndreas Gohr        $ua      = addslashes($agent);
59014d99ec0SAndreas Gohr        $ua_type = '';
59114d99ec0SAndreas Gohr        $ua_ver  = '';
59214d99ec0SAndreas Gohr        $os      = '';
59314d99ec0SAndreas Gohr        $ua_info = addslashes($this->ua_info($agent,$ua_type,$ua_ver,$os));
59414d99ec0SAndreas Gohr
5951878f16fSAndreas Gohr        $page    = addslashes($_REQUEST['p']);
5961878f16fSAndreas Gohr        $ip      = addslashes($_SERVER['REMOTE_ADDR']);
5971878f16fSAndreas Gohr        $sx      = (int) $_REQUEST['sx'];
5981878f16fSAndreas Gohr        $sy      = (int) $_REQUEST['sy'];
5991878f16fSAndreas Gohr        $vx      = (int) $_REQUEST['vx'];
6001878f16fSAndreas Gohr        $vy      = (int) $_REQUEST['vy'];
6011878f16fSAndreas Gohr        $user    = addslashes($_SERVER['REMOTE_USER']);
6021878f16fSAndreas Gohr        $session = addslashes(session_id());
6031878f16fSAndreas Gohr
60494171ff3SAndreas Gohr        $sql  = "INSERT DELAYED INTO ".$this->getConf('db_prefix')."access
6051878f16fSAndreas Gohr                    SET page     = '$page',
6061878f16fSAndreas Gohr                        ip       = '$ip',
6071878f16fSAndreas Gohr                        ua       = '$ua',
6081878f16fSAndreas Gohr                        ua_info  = '$ua_info',
60914d99ec0SAndreas Gohr                        ua_type  = '$ua_type',
61014d99ec0SAndreas Gohr                        ua_ver   = '$ua_ver',
61114d99ec0SAndreas Gohr                        os       = '$os',
6121878f16fSAndreas Gohr                        ref      = '$ref',
61394171ff3SAndreas Gohr                        ref_md5  = '$ref_md5',
61414d99ec0SAndreas Gohr                        ref_type = '$ref_type',
6151878f16fSAndreas Gohr                        screen_x = '$sx',
6161878f16fSAndreas Gohr                        screen_y = '$sy',
6171878f16fSAndreas Gohr                        view_x   = '$vx',
6181878f16fSAndreas Gohr                        view_y   = '$vy',
6191878f16fSAndreas Gohr                        user     = '$user',
6201878f16fSAndreas Gohr                        session  = '$session'";
6211878f16fSAndreas Gohr        $ok = $this->runSQL($sql);
6221878f16fSAndreas Gohr        if(is_null($ok)){
6231878f16fSAndreas Gohr            global $MSG;
6241878f16fSAndreas Gohr            print_r($MSG);
6251878f16fSAndreas Gohr        }
62614d99ec0SAndreas Gohr
62714d99ec0SAndreas Gohr        // resolve the IP
62814d99ec0SAndreas Gohr        $this->log_ip($_SERVER['REMOTE_ADDR']);
6291878f16fSAndreas Gohr    }
6301878f16fSAndreas Gohr
6311878f16fSAndreas Gohr    /**
6321878f16fSAndreas Gohr     * Just send a 1x1 pixel blank gif to the browser
6331878f16fSAndreas Gohr     *
6341878f16fSAndreas Gohr     * @called from log.php
6351878f16fSAndreas Gohr     *
6361878f16fSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
6371878f16fSAndreas Gohr     * @author Harry Fuecks <fuecks@gmail.com>
6381878f16fSAndreas Gohr     */
6391878f16fSAndreas Gohr    function sendGIF(){
6401878f16fSAndreas Gohr        $img = base64_decode('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7');
6411878f16fSAndreas Gohr        header('Content-Type: image/gif');
6421878f16fSAndreas Gohr        header('Content-Length: '.strlen($img));
6431878f16fSAndreas Gohr        header('Connection: Close');
6441878f16fSAndreas Gohr        print $img;
6451878f16fSAndreas Gohr        flush();
6461878f16fSAndreas Gohr        // Browser should drop connection after this
6471878f16fSAndreas Gohr        // Thinks it's got the whole image
6481878f16fSAndreas Gohr    }
6491878f16fSAndreas Gohr
6501878f16fSAndreas Gohr}
651