xref: /plugin/statistics/admin.php (revision c73e16f189f03bb9b4fcdad5da8027d9806f7bba)
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() {
749da6395dSAndreas Gohr        $this->html_toc();
75264f1744SAndreas Gohr        echo '<h1>Access Statistics</h1>';
76264f1744SAndreas Gohr        $this->html_timeselect();
77264f1744SAndreas Gohr
78264f1744SAndreas Gohr        switch($this->opt){
799da6395dSAndreas Gohr            case 'country':
809da6395dSAndreas Gohr                $this->html_country();
819da6395dSAndreas Gohr                break;
829da6395dSAndreas Gohr            case 'page':
839da6395dSAndreas Gohr                $this->html_page();
849da6395dSAndreas Gohr                break;
8575fa767dSAndreas Gohr            case 'browser':
8675fa767dSAndreas Gohr                $this->html_browser();
8775fa767dSAndreas Gohr                break;
88bd4217d3SAndreas Gohr            case 'os':
89bd4217d3SAndreas Gohr                $this->html_os();
90bd4217d3SAndreas Gohr                break;
919da6395dSAndreas Gohr            case 'referer':
929da6395dSAndreas Gohr                $this->html_referer();
939da6395dSAndreas Gohr                break;
94e7a2f1e0SAndreas Gohr            case 'newreferer':
95e7a2f1e0SAndreas Gohr                $this->html_newreferer();
96e7a2f1e0SAndreas Gohr                break;
97*c73e16f1SAndreas Gohr            case 'resolution':
98*c73e16f1SAndreas Gohr                $this->html_resolution();
99*c73e16f1SAndreas Gohr                break;
10014d99ec0SAndreas Gohr            default:
1019da6395dSAndreas Gohr                $this->html_dashboard();
10214d99ec0SAndreas Gohr        }
10314d99ec0SAndreas Gohr    }
10414d99ec0SAndreas Gohr
1059da6395dSAndreas Gohr    function html_toc(){
1069da6395dSAndreas Gohr        echo '<div class="toc">';
1079da6395dSAndreas Gohr        echo '<div class="tocheader toctoggle" id="toc__header">';
1089da6395dSAndreas Gohr        echo 'Detailed Statistics';
1099da6395dSAndreas Gohr        echo '</div>';
1109da6395dSAndreas Gohr        echo '<div id="toc__inside">';
1119da6395dSAndreas Gohr        echo '<ul class="toc">';
1129da6395dSAndreas Gohr
1139da6395dSAndreas Gohr        echo '<li><div class="li">';
1142507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=&amp;f='.$this->from.'&amp;t='.$this->to.'">Dashboard</a>';
1159da6395dSAndreas Gohr        echo '</div></li>';
1169da6395dSAndreas Gohr
1179da6395dSAndreas Gohr        echo '<li><div class="li">';
1182507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=page&amp;f='.$this->from.'&amp;t='.$this->to.'">Pages</a>';
1199da6395dSAndreas Gohr        echo '</div></li>';
1209da6395dSAndreas Gohr
1219da6395dSAndreas Gohr        echo '<li><div class="li">';
1222507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=referer&amp;f='.$this->from.'&amp;t='.$this->to.'">Incoming Links</a>';
1239da6395dSAndreas Gohr        echo '</div></li>';
1249da6395dSAndreas Gohr
1259da6395dSAndreas Gohr        echo '<li><div class="li">';
1262507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=newreferer&amp;f='.$this->from.'&amp;t='.$this->to.'">New Incoming Links</a>';
127e7a2f1e0SAndreas Gohr        echo '</div></li>';
128e7a2f1e0SAndreas Gohr
129e7a2f1e0SAndreas Gohr        echo '<li><div class="li">';
1302507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=browser&amp;f='.$this->from.'&amp;t='.$this->to.'">Browsers</a>';
13175fa767dSAndreas Gohr        echo '</div></li>';
13275fa767dSAndreas Gohr
13375fa767dSAndreas Gohr        echo '<li><div class="li">';
1342507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=os&amp;f='.$this->from.'&amp;t='.$this->to.'">Operating Systems</a>';
135bd4217d3SAndreas Gohr        echo '</div></li>';
136bd4217d3SAndreas Gohr
137bd4217d3SAndreas Gohr        echo '<li><div class="li">';
1382507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=country&amp;f='.$this->from.'&amp;t='.$this->to.'">Countries</a>';
1399da6395dSAndreas Gohr        echo '</div></li>';
1409da6395dSAndreas Gohr
141*c73e16f1SAndreas Gohr        echo '<li><div class="li">';
142*c73e16f1SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=resolution&amp;f='.$this->from.'&amp;t='.$this->to.'">Resolution</a>';
143*c73e16f1SAndreas Gohr        echo '</div></li>';
144*c73e16f1SAndreas Gohr
1459da6395dSAndreas Gohr        echo '</ul>';
1469da6395dSAndreas Gohr        echo '</div>';
1479da6395dSAndreas Gohr        echo '</div>';
1489da6395dSAndreas Gohr    }
1499da6395dSAndreas Gohr
1502507f8e0SAndreas Gohr    function html_pager($limit,$next){
1512507f8e0SAndreas Gohr        echo '<div class="plg_stats_pager">';
1522507f8e0SAndreas Gohr
1532507f8e0SAndreas Gohr        if($this->start > 0){
1542507f8e0SAndreas Gohr            $go = max($this->start - $limit, 0);
1552507f8e0SAndreas Gohr            echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$this->from.'&amp;t='.$this->to.'&amp;s='.$go.'" class="prev">previous page</a>';
1562507f8e0SAndreas Gohr        }
1572507f8e0SAndreas Gohr
1582507f8e0SAndreas Gohr        if($next){
1592507f8e0SAndreas Gohr            $go = $this->start + $limit;
1602507f8e0SAndreas Gohr            echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$this->from.'&amp;t='.$this->to.'&amp;s='.$go.'" class="next">next page</a>';
1612507f8e0SAndreas Gohr        }
1622507f8e0SAndreas Gohr        echo '</div>';
1632507f8e0SAndreas Gohr    }
1642507f8e0SAndreas Gohr
165264f1744SAndreas Gohr    /**
166264f1744SAndreas Gohr     * Print the time selection menu
167264f1744SAndreas Gohr     */
16814d99ec0SAndreas Gohr    function html_timeselect(){
169264f1744SAndreas Gohr        $now   = date('Y-m-d');
170264f1744SAndreas Gohr        $yday  = date('Y-m-d',time()-(60*60*24));
171264f1744SAndreas Gohr        $week  = date('Y-m-d',time()-(60*60*24*7));
172264f1744SAndreas Gohr        $month = date('Y-m-d',time()-(60*60*24*30));
17314d99ec0SAndreas Gohr
174264f1744SAndreas Gohr        echo '<div class="plg_stats_timeselect">';
175264f1744SAndreas Gohr        echo '<span>Select the timeframe:</span>';
176264f1744SAndreas Gohr        echo '<ul>';
177264f1744SAndreas Gohr
178264f1744SAndreas Gohr        echo '<li>';
1792507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$now.'&amp;t='.$now.'">';
180264f1744SAndreas Gohr        echo 'today';
181264f1744SAndreas Gohr        echo '</a>';
182264f1744SAndreas Gohr        echo '</li>';
183264f1744SAndreas Gohr
184264f1744SAndreas Gohr        echo '<li>';
1852507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$yday.'&amp;t='.$yday.'">';
186264f1744SAndreas Gohr        echo 'yesterday';
187264f1744SAndreas Gohr        echo '</a>';
188264f1744SAndreas Gohr        echo '</li>';
189264f1744SAndreas Gohr
190264f1744SAndreas Gohr        echo '<li>';
1912507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$week.'&amp;t='.$now.'">';
192264f1744SAndreas Gohr        echo 'last 7 days';
193264f1744SAndreas Gohr        echo '</a>';
194264f1744SAndreas Gohr        echo '</li>';
195264f1744SAndreas Gohr
196264f1744SAndreas Gohr        echo '<li>';
1972507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt='.$this->opt.'&amp;f='.$month.'&amp;t='.$now.'">';
198264f1744SAndreas Gohr        echo 'last 30 days';
199264f1744SAndreas Gohr        echo '</a>';
200264f1744SAndreas Gohr        echo '</li>';
201264f1744SAndreas Gohr
202264f1744SAndreas Gohr        echo '</ul>';
203264f1744SAndreas Gohr
204264f1744SAndreas Gohr
205264f1744SAndreas Gohr        echo '<form action="" method="get">';
206264f1744SAndreas Gohr        echo '<input type="hidden" name="do" value="admin" />';
207264f1744SAndreas Gohr        echo '<input type="hidden" name="page" value="statistics" />';
208264f1744SAndreas Gohr        echo '<input type="hidden" name="opt" value="'.$this->opt.'" />';
209264f1744SAndreas Gohr        echo '<input type="text" name="f" value="'.$this->from.'" class="edit" />';
210264f1744SAndreas Gohr        echo '<input type="text" name="t" value="'.$this->to.'" class="edit" />';
211264f1744SAndreas Gohr        echo '<input type="submit" value="go" class="button" />';
21214d99ec0SAndreas Gohr        echo '</form>';
213264f1744SAndreas Gohr
214264f1744SAndreas Gohr        echo '</div>';
21514d99ec0SAndreas Gohr    }
21614d99ec0SAndreas Gohr
21714d99ec0SAndreas Gohr
218f5f32cbfSAndreas Gohr    /**
219f5f32cbfSAndreas Gohr     * Print an introductionary screen
220f5f32cbfSAndreas Gohr     */
22114d99ec0SAndreas Gohr    function html_dashboard(){
2222812a751SAndreas Gohr        echo '<p>This page gives you a quick overview on what is happening in your Wiki. For detailed lists
2232812a751SAndreas Gohr              choose a topic from the list.</p>';
2242812a751SAndreas Gohr
2252812a751SAndreas Gohr
226264f1744SAndreas Gohr        echo '<div class="plg_stats_dashboard">';
227264f1744SAndreas Gohr
2282812a751SAndreas Gohr        // general info
2292812a751SAndreas Gohr        echo '<div class="plg_stats_top">';
2302812a751SAndreas Gohr        $result = $this->sql_aggregate($this->tlimit);
2312812a751SAndreas Gohr        echo '<ul>';
2322812a751SAndreas Gohr        echo '<li><span>'.$result['pageviews'].'</span> page views</li>';
2332812a751SAndreas Gohr        echo '<li><span>'.$result['sessions'].'</span> visitors (sessions)</li>';
2342812a751SAndreas Gohr        echo '<li><span>'.$result['users'].'</span> logged in users</li>';
2352812a751SAndreas Gohr
2362812a751SAndreas Gohr        echo '</ul>';
2372812a751SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=trend&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
2382812a751SAndreas Gohr        echo '</div>';
2392812a751SAndreas Gohr
24014d99ec0SAndreas Gohr
24187d5e44bSAndreas Gohr        // top pages today
242264f1744SAndreas Gohr        echo '<div>';
243264f1744SAndreas Gohr        echo '<h2>Most popular pages</h2>';
24495eb68e6SAndreas Gohr        $result = $this->sql_pages($this->tlimit,$this->start,15);
2452812a751SAndreas Gohr        $this->html_resulttable($result);
2462507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=page&amp;f='.$this->from.'&amp;t='.$this->to.'" class="more">more</a>';
247264f1744SAndreas Gohr        echo '</div>';
24887d5e44bSAndreas Gohr
24987d5e44bSAndreas Gohr        // top referer today
250264f1744SAndreas Gohr        echo '<div>';
251e7a2f1e0SAndreas Gohr        echo '<h2>Newest incoming links</h2>';
252e7a2f1e0SAndreas Gohr        $result = $this->sql_newreferer($this->tlimit,$this->start,15);
2532812a751SAndreas Gohr        $this->html_resulttable($result);
2542507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=newreferer&amp;f='.$this->from.'&amp;t='.$this->to.'" class="more">more</a>';
255264f1744SAndreas Gohr        echo '</div>';
25654f6c432SAndreas Gohr
25754f6c432SAndreas Gohr        // top countries today
258264f1744SAndreas Gohr        echo '<div>';
259264f1744SAndreas Gohr        echo '<h2>Visitor\'s top countries</h2>';
26095eb68e6SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=country&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
2612507f8e0SAndreas Gohr        echo '<a href="?do=admin&amp;page=statistics&amp;opt=country&amp;f='.$this->from.'&amp;t='.$this->to.'" class="more">more</a>';
262264f1744SAndreas Gohr        echo '</div>';
263264f1744SAndreas Gohr
264264f1744SAndreas Gohr        echo '</div>';
26514d99ec0SAndreas Gohr    }
26614d99ec0SAndreas Gohr
2679da6395dSAndreas Gohr    function html_country(){
2689da6395dSAndreas Gohr        echo '<div class="plg_stats_full">';
2699da6395dSAndreas Gohr        echo '<h2>Visitor\'s Countries</h2>';
270bd4217d3SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=country&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
2719da6395dSAndreas Gohr        $result = $this->sql_countries($this->tlimit,$this->start,150);
2722507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
2739da6395dSAndreas Gohr        echo '</div>';
2749da6395dSAndreas Gohr    }
2759da6395dSAndreas Gohr
2769da6395dSAndreas Gohr    function html_page(){
2779da6395dSAndreas Gohr        echo '<div class="plg_stats_full">';
2789da6395dSAndreas Gohr        echo '<h2>Popular Pages</h2>';
2799da6395dSAndreas Gohr        $result = $this->sql_pages($this->tlimit,$this->start,150);
2802507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
2819da6395dSAndreas Gohr        echo '</div>';
2829da6395dSAndreas Gohr    }
2839da6395dSAndreas Gohr
28475fa767dSAndreas Gohr    function html_browser(){
28575fa767dSAndreas Gohr        echo '<div class="plg_stats_full">';
28675fa767dSAndreas Gohr        echo '<h2>Browser Shootout</h2>';
28775fa767dSAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=browser&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
28875fa767dSAndreas Gohr        $result = $this->sql_browsers($this->tlimit,$this->start,150,true);
2892507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
29075fa767dSAndreas Gohr        echo '</div>';
29175fa767dSAndreas Gohr    }
29275fa767dSAndreas Gohr
293bd4217d3SAndreas Gohr    function html_os(){
294bd4217d3SAndreas Gohr        echo '<div class="plg_stats_full">';
295bd4217d3SAndreas Gohr        echo '<h2>Operating Systems</h2>';
296bd4217d3SAndreas Gohr        $result = $this->sql_os($this->tlimit,$this->start,150,true);
2972507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
298bd4217d3SAndreas Gohr        echo '</div>';
299bd4217d3SAndreas Gohr    }
300bd4217d3SAndreas Gohr
3019da6395dSAndreas Gohr    function html_referer(){
3029da6395dSAndreas Gohr        echo '<div class="plg_stats_full">';
3039da6395dSAndreas Gohr        echo '<h2>Incoming Links</h2>';
3042812a751SAndreas Gohr        $result = $this->sql_aggregate($this->tlimit);
3052812a751SAndreas Gohr
3062812a751SAndreas Gohr        $all    = $result['search']+$result['external']+$result['direct'];
3072812a751SAndreas Gohr
30894023548SAndreas Gohr        if($all){
3092812a751SAndreas Gohr            printf("<p>Of all %d external visits, %d (%.1f%%) were bookmarked (direct) accesses,
3102812a751SAndreas Gohr                    %d (%.1f%%) came from search engines and %d (%.1f%%) were referred through
3112812a751SAndreas Gohr                    links from other pages.</p>",$all,$result['direct'],(100*$result['direct']/$all),
3122812a751SAndreas Gohr                    $result['search'],(100*$result['search']/$all),$result['external'],
3132812a751SAndreas Gohr                    (100*$result['external']/$all));
31494023548SAndreas Gohr        }
3152812a751SAndreas Gohr
3169da6395dSAndreas Gohr        $result = $this->sql_referer($this->tlimit,$this->start,150);
3172507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
3189da6395dSAndreas Gohr        echo '</div>';
3199da6395dSAndreas Gohr    }
3209da6395dSAndreas Gohr
321e7a2f1e0SAndreas Gohr    function html_newreferer(){
322e7a2f1e0SAndreas Gohr        echo '<div class="plg_stats_full">';
323e7a2f1e0SAndreas Gohr        echo '<h2>New Incoming Links</h2>';
324e7a2f1e0SAndreas Gohr        echo '<p>The following incoming links where first logged in the selected time frame,
325e7a2f1e0SAndreas Gohr              and have never been seen before.</p>';
326e7a2f1e0SAndreas Gohr
327e7a2f1e0SAndreas Gohr        $result = $this->sql_newreferer($this->tlimit,$this->start,150);
3282507f8e0SAndreas Gohr        $this->html_resulttable($result,'',150);
329e7a2f1e0SAndreas Gohr        echo '</div>';
330e7a2f1e0SAndreas Gohr    }
331e7a2f1e0SAndreas Gohr
332*c73e16f1SAndreas Gohr    function html_resolution(){
333*c73e16f1SAndreas Gohr        echo '<div class="plg_stats_full">';
334*c73e16f1SAndreas Gohr        echo '<h2>Resolution</h2>';
335*c73e16f1SAndreas Gohr        $result = $this->sql_resolution($this->tlimit,$this->start,150);
336*c73e16f1SAndreas Gohr        $this->html_resulttable($result,'',150);
337*c73e16f1SAndreas Gohr
338*c73e16f1SAndreas Gohr        echo '<p>While the data above gives you some info about the resolution your visitors use, it does not tell you
339*c73e16f1SAndreas Gohr              much about about the real size of their browser windows. The graphic below shows the size distribution of
340*c73e16f1SAndreas Gohr              the view port (document area) of your visitor\'s browsers. Please note that this data can not be logged
341*c73e16f1SAndreas Gohr              in all browsers. Because users may resize their browser window while browsing your site the statistics may
342*c73e16f1SAndreas Gohr              be flawed. Take it with a grain of salt.</p>';
343*c73e16f1SAndreas Gohr
344*c73e16f1SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/img.php?img=view&amp;f='.$this->from.'&amp;t='.$this->to.'" />';
345*c73e16f1SAndreas Gohr        echo '</div>';
346*c73e16f1SAndreas Gohr    }
3479da6395dSAndreas Gohr
3489da6395dSAndreas Gohr
34914d99ec0SAndreas Gohr    /**
35014d99ec0SAndreas Gohr     * Display a result in a HTML table
35114d99ec0SAndreas Gohr     */
3522507f8e0SAndreas Gohr    function html_resulttable($result,$header='',$pager=0){
35314d99ec0SAndreas Gohr        echo '<table>';
3542812a751SAndreas Gohr        if(is_array($header)){
35514d99ec0SAndreas Gohr            echo '<tr>';
35614d99ec0SAndreas Gohr            foreach($header as $h){
35714d99ec0SAndreas Gohr                echo '<th>'.hsc($h).'</th>';
35814d99ec0SAndreas Gohr            }
35914d99ec0SAndreas Gohr            echo '</tr>';
3602812a751SAndreas Gohr        }
36114d99ec0SAndreas Gohr
3622507f8e0SAndreas Gohr        $count = 0;
36314d99ec0SAndreas Gohr        foreach($result as $row){
36414d99ec0SAndreas Gohr            echo '<tr>';
36514d99ec0SAndreas Gohr            foreach($row as $k => $v){
3662812a751SAndreas Gohr                echo '<td class="plg_stats_X'.$k.'">';
36714d99ec0SAndreas Gohr                if($k == 'page'){
36814d99ec0SAndreas Gohr                    echo '<a href="'.wl($v).'" class="wikilink1">';
36914d99ec0SAndreas Gohr                    echo hsc($v);
37014d99ec0SAndreas Gohr                    echo '</a>';
37114d99ec0SAndreas Gohr                }elseif($k == 'url'){
37254f6c432SAndreas Gohr                    $url = hsc($v);
3732812a751SAndreas Gohr                    if(strlen($url) > 45){
3742812a751SAndreas Gohr                        $url = substr($url,0,30).' &hellip; '.substr($url,-15);
37554f6c432SAndreas Gohr                    }
37614d99ec0SAndreas Gohr                    echo '<a href="'.$v.'" class="urlextern">';
37754f6c432SAndreas Gohr                    echo $url;
37814d99ec0SAndreas Gohr                    echo '</a>';
37975fa767dSAndreas Gohr                }elseif($k == 'browser'){
38075fa767dSAndreas Gohr                    include_once(dirname(__FILE__).'/inc/browsers.php');
38175fa767dSAndreas Gohr                    echo $BrowsersHashIDLib[$v];
38275fa767dSAndreas Gohr                }elseif($k == 'bflag'){
38375fa767dSAndreas Gohr                    include_once(dirname(__FILE__).'/inc/browsers.php');
38475fa767dSAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/browser/'.$BrowsersHashIcon[$v].'.png" alt="'.hsc($v).'" />';
385bd4217d3SAndreas Gohr                }elseif($k == 'os'){
386bd4217d3SAndreas Gohr                    if(empty($v)){
387bd4217d3SAndreas Gohr                        echo 'unknown';
388bd4217d3SAndreas Gohr                    }else{
389bd4217d3SAndreas Gohr                        include_once(dirname(__FILE__).'/inc/operating_systems.php');
390bd4217d3SAndreas Gohr                        echo $OSHashLib[$v];
391bd4217d3SAndreas Gohr                    }
392bd4217d3SAndreas Gohr                }elseif($k == 'osflag'){
393bd4217d3SAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/os/'.hsc($v).'.png" alt="'.hsc($v).'" />';
39475fa767dSAndreas Gohr                }elseif($k == 'cflag'){
39575fa767dSAndreas Gohr                    echo '<img src="'.DOKU_BASE.'lib/plugins/statistics/ico/flags/'.hsc($v).'.png" alt="'.hsc($v).'" width="18" height="12" />';
39614d99ec0SAndreas Gohr                }elseif($k == 'html'){
39714d99ec0SAndreas Gohr                    echo $v;
39814d99ec0SAndreas Gohr                }else{
39914d99ec0SAndreas Gohr                    echo hsc($v);
40014d99ec0SAndreas Gohr                }
40114d99ec0SAndreas Gohr                echo '</td>';
40214d99ec0SAndreas Gohr            }
40314d99ec0SAndreas Gohr            echo '</tr>';
4042507f8e0SAndreas Gohr
4052507f8e0SAndreas Gohr            if($pager && ($count == $pager)) break;
4062507f8e0SAndreas Gohr            $count++;
40714d99ec0SAndreas Gohr        }
40814d99ec0SAndreas Gohr        echo '</table>';
4092507f8e0SAndreas Gohr
4102507f8e0SAndreas Gohr        if($pager) $this->html_pager($pager,count($result) > $pager);
4111878f16fSAndreas Gohr    }
4121878f16fSAndreas Gohr
41395eb68e6SAndreas Gohr    /**
41495eb68e6SAndreas Gohr     * Create an image
41595eb68e6SAndreas Gohr     */
41695eb68e6SAndreas Gohr    function img_build($img){
41795eb68e6SAndreas Gohr        include(dirname(__FILE__).'/inc/AGC.class.php');
41895eb68e6SAndreas Gohr
41995eb68e6SAndreas Gohr        switch($img){
42095eb68e6SAndreas Gohr            case 'country':
42195eb68e6SAndreas Gohr                // build top countries + other
42295eb68e6SAndreas Gohr                $result = $this->sql_countries($this->tlimit,$this->start,0);
42395eb68e6SAndreas Gohr                $data = array();
42495eb68e6SAndreas Gohr                $top = 0;
42595eb68e6SAndreas Gohr                foreach($result as $row){
42695eb68e6SAndreas Gohr                    if($top < 7){
42795eb68e6SAndreas Gohr                        $data[$row['country']] = $row['cnt'];
42895eb68e6SAndreas Gohr                    }else{
42995eb68e6SAndreas Gohr                        $data['other'] += $row['cnt'];
43095eb68e6SAndreas Gohr                    }
43195eb68e6SAndreas Gohr                    $top++;
43295eb68e6SAndreas Gohr                }
43395eb68e6SAndreas Gohr                $pie = new AGC(300, 200);
43495eb68e6SAndreas Gohr                $pie->setProp("showkey",true);
43595eb68e6SAndreas Gohr                $pie->setProp("showval",false);
43695eb68e6SAndreas Gohr                $pie->setProp("showgrid",false);
43795eb68e6SAndreas Gohr                $pie->setProp("type","pie");
43895eb68e6SAndreas Gohr                $pie->setProp("keyinfo",1);
43995eb68e6SAndreas Gohr                $pie->setProp("keysize",8);
44095eb68e6SAndreas Gohr                $pie->setProp("keywidspc",-50);
44195eb68e6SAndreas Gohr                $pie->setProp("key",array_keys($data));
44295eb68e6SAndreas Gohr                $pie->addBulkPoints(array_values($data));
44395eb68e6SAndreas Gohr                @$pie->graph();
44495eb68e6SAndreas Gohr                $pie->showGraph();
44595eb68e6SAndreas Gohr                break;
44675fa767dSAndreas Gohr            case 'browser':
44775fa767dSAndreas Gohr                // build top browsers + other
44875fa767dSAndreas Gohr                include_once(dirname(__FILE__).'/inc/browsers.php');
44975fa767dSAndreas Gohr
45075fa767dSAndreas Gohr                $result = $this->sql_browsers($this->tlimit,$this->start,0,false);
45175fa767dSAndreas Gohr                $data = array();
45275fa767dSAndreas Gohr                $top = 0;
45375fa767dSAndreas Gohr                foreach($result as $row){
45475fa767dSAndreas Gohr                    if($top < 5){
45575fa767dSAndreas Gohr                        $data[strip_tags($BrowsersHashIDLib[$row['ua_info']])] = $row['cnt'];
45675fa767dSAndreas Gohr                    }else{
45775fa767dSAndreas Gohr                        $data['other'] += $row['cnt'];
45875fa767dSAndreas Gohr                    }
45975fa767dSAndreas Gohr                    $top++;
46075fa767dSAndreas Gohr                }
46175fa767dSAndreas Gohr                $pie = new AGC(300, 200);
46275fa767dSAndreas Gohr                $pie->setProp("showkey",true);
46375fa767dSAndreas Gohr                $pie->setProp("showval",false);
46475fa767dSAndreas Gohr                $pie->setProp("showgrid",false);
46575fa767dSAndreas Gohr                $pie->setProp("type","pie");
46675fa767dSAndreas Gohr                $pie->setProp("keyinfo",1);
46775fa767dSAndreas Gohr                $pie->setProp("keysize",8);
46875fa767dSAndreas Gohr                $pie->setProp("keywidspc",-50);
46975fa767dSAndreas Gohr                $pie->setProp("key",array_keys($data));
47075fa767dSAndreas Gohr                $pie->addBulkPoints(array_values($data));
47175fa767dSAndreas Gohr                @$pie->graph();
47275fa767dSAndreas Gohr                $pie->showGraph();
47375fa767dSAndreas Gohr                break;
474*c73e16f1SAndreas Gohr            case 'view':
475*c73e16f1SAndreas Gohr
476*c73e16f1SAndreas Gohr                $graph = new AGC(400, 200);
477*c73e16f1SAndreas Gohr                $graph->setColor('color',0,'blue');
478*c73e16f1SAndreas Gohr                $graph->setColor('color',1,'red');
479*c73e16f1SAndreas Gohr                $graph->setProp("showkey",true);
480*c73e16f1SAndreas Gohr                $graph->setProp("key",'view port width',0);
481*c73e16f1SAndreas Gohr                $graph->setProp("key",'view port height',1);
482*c73e16f1SAndreas Gohr
483*c73e16f1SAndreas Gohr                $result = $this->sql_viewport($this->tlimit,0,0,true);
484*c73e16f1SAndreas Gohr                foreach($result as $row){
485*c73e16f1SAndreas Gohr                    $graph->addPoint($row['cnt'],$row['res_x'],0);
486*c73e16f1SAndreas Gohr                }
487*c73e16f1SAndreas Gohr
488*c73e16f1SAndreas Gohr                $result = $this->sql_viewport($this->tlimit,0,0,false);
489*c73e16f1SAndreas Gohr                foreach($result as $row){
490*c73e16f1SAndreas Gohr                    $graph->addPoint($row['cnt'],$row['res_y'],1);
491*c73e16f1SAndreas Gohr                }
492*c73e16f1SAndreas Gohr
493*c73e16f1SAndreas Gohr                @$graph->graph();
494*c73e16f1SAndreas Gohr                $graph->showGraph();
495*c73e16f1SAndreas Gohr
496*c73e16f1SAndreas Gohr                break;
4972812a751SAndreas Gohr            case 'trend':
4982812a751SAndreas Gohr                $hours  = ($this->from == $this->to);
4992812a751SAndreas Gohr                $result = $this->sql_trend($this->tlimit,$hours);
5002812a751SAndreas Gohr                $data1   = array();
5012812a751SAndreas Gohr                $data2   = array();
5022812a751SAndreas Gohr
5032812a751SAndreas Gohr                $graph = new AGC(400, 150);
5042812a751SAndreas Gohr                $graph->setProp("type","bar");
5052812a751SAndreas Gohr                $graph->setProp("showgrid",false);
5062812a751SAndreas Gohr                $graph->setProp("barwidth",.8);
50775fa767dSAndreas Gohr
5082812a751SAndreas Gohr                $graph->setColor('color',0,'blue');
5092812a751SAndreas Gohr                $graph->setColor('color',1,'red');
5102812a751SAndreas Gohr
5112812a751SAndreas Gohr                if($hours){
5122812a751SAndreas Gohr                    //preset $hours
5132812a751SAndreas Gohr                    for($i=0;$i<24;$i++){
5142812a751SAndreas Gohr                        $data1[$i] = 0;
5152812a751SAndreas Gohr                        $data2[$i] = 0;
5162812a751SAndreas Gohr                        $graph->setProp("scale",array(' 0h','   4h','   8h','    12h','    16h','    20h','    24h'));
5172812a751SAndreas Gohr                    }
5182812a751SAndreas Gohr                }else{
5192812a751SAndreas Gohr                    $graph->setProp("scale",array(next(array_keys($data1)),$this->to));
5202812a751SAndreas Gohr                }
5212812a751SAndreas Gohr
5222812a751SAndreas Gohr                foreach($result as $row){
5232812a751SAndreas Gohr                    $data1[$row['time']] = $row['pageviews'];
5242812a751SAndreas Gohr                    $data2[$row['time']] = $row['sessions'];
5252812a751SAndreas Gohr                }
5262812a751SAndreas Gohr
5272812a751SAndreas Gohr                foreach($data1 as $key => $val){
5282812a751SAndreas Gohr                    $graph->addPoint($val,$key,0);
5292812a751SAndreas Gohr                }
5302812a751SAndreas Gohr                foreach($data2 as $key => $val){
5312812a751SAndreas Gohr                    $graph->addPoint($val,$key,1);
5322812a751SAndreas Gohr                }
5332812a751SAndreas Gohr
5342812a751SAndreas Gohr                @$graph->graph();
5352812a751SAndreas Gohr                $graph->showGraph();
5362812a751SAndreas Gohr
53795eb68e6SAndreas Gohr            default:
53895eb68e6SAndreas Gohr                $this->sendGIF();
53995eb68e6SAndreas Gohr        }
54095eb68e6SAndreas Gohr    }
54195eb68e6SAndreas Gohr
54295eb68e6SAndreas Gohr
5432812a751SAndreas Gohr    /**
5442812a751SAndreas Gohr     * Return some aggregated statistics
5452812a751SAndreas Gohr     */
5462812a751SAndreas Gohr    function sql_aggregate($tlimit){
5472812a751SAndreas Gohr        $data = array();
5482812a751SAndreas Gohr
5492812a751SAndreas Gohr        $sql = "SELECT ref_type, COUNT(*) as cnt
5502812a751SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
5512812a751SAndreas Gohr                 WHERE $tlimit
5522812a751SAndreas Gohr                   AND ua_type = 'browser'
5532812a751SAndreas Gohr              GROUP BY ref_type";
5542812a751SAndreas Gohr        $result = $this->runSQL($sql);
5552812a751SAndreas Gohr
5562812a751SAndreas Gohr        foreach($result as $row){
5572812a751SAndreas Gohr            if($row['ref_type'] == 'search')   $data['search']   = $row['cnt'];
5582812a751SAndreas Gohr            if($row['ref_type'] == 'external') $data['external'] = $row['cnt'];
5592812a751SAndreas Gohr            if($row['ref_type'] == 'internal') $data['internal'] = $row['cnt'];
5602812a751SAndreas Gohr            if($row['ref_type'] == '')         $data['direct']   = $row['cnt'];
5612812a751SAndreas Gohr        }
5622812a751SAndreas Gohr
5632812a751SAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as sessions,
5642812a751SAndreas Gohr                       COUNT(session) as views,
5652812a751SAndreas Gohr                       COUNT(DISTINCT user) as users
5662812a751SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
5672812a751SAndreas Gohr                 WHERE $tlimit
5682812a751SAndreas Gohr                   AND ua_type = 'browser'";
5692812a751SAndreas Gohr        $result = $this->runSQL($sql);
5702812a751SAndreas Gohr
57175fa767dSAndreas Gohr        $data['users']     = max($result[0]['users'] - 1,0); // subtract empty user
5722812a751SAndreas Gohr        $data['sessions']  = $result[0]['sessions'];
5732812a751SAndreas Gohr        $data['pageviews'] = $result[0]['views'];
5742812a751SAndreas Gohr
5752812a751SAndreas Gohr        $sql = "SELECT COUNT(id) as robots
5762812a751SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
5772812a751SAndreas Gohr                 WHERE $tlimit
5782812a751SAndreas Gohr                   AND ua_type = 'robot'";
5792812a751SAndreas Gohr        $result = $this->runSQL($sql);
5802812a751SAndreas Gohr        $data['robots'] = $result[0]['robots'];
5812812a751SAndreas Gohr
5822812a751SAndreas Gohr        return $data;
5832812a751SAndreas Gohr    }
5842812a751SAndreas Gohr
585bd4217d3SAndreas Gohr    /**
586bd4217d3SAndreas Gohr     * standard statistics follow, only accesses made by browsers are counted
587bd4217d3SAndreas Gohr     * for general stats like browser or OS only visitors not pageviews are counted
588bd4217d3SAndreas Gohr     */
5892812a751SAndreas Gohr    function sql_trend($tlimit,$hours=false){
5902812a751SAndreas Gohr        if($hours){
5912812a751SAndreas Gohr            $sql = "SELECT HOUR(dt) as time,
5922812a751SAndreas Gohr                           COUNT(DISTINCT session) as sessions,
5932812a751SAndreas Gohr                           COUNT(session) as pageviews
5942812a751SAndreas Gohr                      FROM ".$this->getConf('db_prefix')."access as A
5952812a751SAndreas Gohr                     WHERE $tlimit
5962812a751SAndreas Gohr                       AND ua_type = 'browser'
5972812a751SAndreas Gohr                  GROUP BY HOUR(dt)
5982812a751SAndreas Gohr                  ORDER BY time";
5992812a751SAndreas Gohr        }else{
6002812a751SAndreas Gohr            $sql = "SELECT DATE(dt) as time,
6012812a751SAndreas Gohr                           COUNT(DISTINCT session) as sessions,
6022812a751SAndreas Gohr                           COUNT(session) as pageviews
6032812a751SAndreas Gohr                      FROM ".$this->getConf('db_prefix')."access as A
6042812a751SAndreas Gohr                     WHERE $tlimit
6052812a751SAndreas Gohr                       AND ua_type = 'browser'
6062812a751SAndreas Gohr                  GROUP BY DATE(dt)
6072812a751SAndreas Gohr                  ORDER BY time";
6082812a751SAndreas Gohr        }
6092812a751SAndreas Gohr        return $this->runSQL($sql);
6102812a751SAndreas Gohr    }
6112812a751SAndreas Gohr
61295eb68e6SAndreas Gohr    function sql_pages($tlimit,$start=0,$limit=20){
6132812a751SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, page
61495eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
61595eb68e6SAndreas Gohr                 WHERE $tlimit
61695eb68e6SAndreas Gohr                   AND ua_type = 'browser'
61795eb68e6SAndreas Gohr              GROUP BY page
61895eb68e6SAndreas Gohr              ORDER BY cnt DESC, page".
61995eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
62095eb68e6SAndreas Gohr        return $this->runSQL($sql);
62195eb68e6SAndreas Gohr    }
62295eb68e6SAndreas Gohr
62395eb68e6SAndreas Gohr    function sql_referer($tlimit,$start=0,$limit=20){
6242812a751SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, ref as url
62595eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
62695eb68e6SAndreas Gohr                 WHERE $tlimit
62795eb68e6SAndreas Gohr                   AND ua_type = 'browser'
62895eb68e6SAndreas Gohr                   AND ref_type = 'external'
62995eb68e6SAndreas Gohr              GROUP BY ref_md5
63095eb68e6SAndreas Gohr              ORDER BY cnt DESC, url".
63195eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
63295eb68e6SAndreas Gohr        return $this->runSQL($sql);
63395eb68e6SAndreas Gohr    }
63495eb68e6SAndreas Gohr
635e7a2f1e0SAndreas Gohr    function sql_newreferer($tlimit,$start=0,$limit=20){
636e7a2f1e0SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, ref as url
637e7a2f1e0SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
638e7a2f1e0SAndreas Gohr                 WHERE ua_type = 'browser'
639e7a2f1e0SAndreas Gohr                   AND ref_type = 'external'
640e7a2f1e0SAndreas Gohr              GROUP BY ref_md5
641e7a2f1e0SAndreas Gohr                HAVING DATE(MIN(dt)) >= DATE('".$this->from."')
642e7a2f1e0SAndreas Gohr                   AND DATE(MIN(dt)) <= DATE('".$this->to."')
643e7a2f1e0SAndreas Gohr              ORDER BY cnt DESC, url".
644e7a2f1e0SAndreas Gohr              $this->sql_limit($start,$limit);
645e7a2f1e0SAndreas Gohr        return $this->runSQL($sql);
646e7a2f1e0SAndreas Gohr    }
647e7a2f1e0SAndreas Gohr
64895eb68e6SAndreas Gohr    function sql_countries($tlimit,$start=0,$limit=20){
649bd4217d3SAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, B.code AS cflag, B.country
65095eb68e6SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A,
65195eb68e6SAndreas Gohr                       ".$this->getConf('db_prefix')."iplocation as B
65295eb68e6SAndreas Gohr                 WHERE $tlimit
65395eb68e6SAndreas Gohr                   AND A.ip = B.ip
65495eb68e6SAndreas Gohr              GROUP BY B.country
65595eb68e6SAndreas Gohr              ORDER BY cnt DESC, B.country".
65695eb68e6SAndreas Gohr              $this->sql_limit($start,$limit);
65795eb68e6SAndreas Gohr        return $this->runSQL($sql);
65895eb68e6SAndreas Gohr    }
65995eb68e6SAndreas Gohr
66075fa767dSAndreas Gohr    function sql_browsers($tlimit,$start=0,$limit=20,$ext=true){
66175fa767dSAndreas Gohr        if($ext){
66275fa767dSAndreas Gohr            $sel = 'ua_info as bflag, ua_info as browser, ua_ver';
66375fa767dSAndreas Gohr            $grp = 'ua_info, ua_ver';
66475fa767dSAndreas Gohr        }else{
66575fa767dSAndreas Gohr            $grp = 'ua_info';
66675fa767dSAndreas Gohr            $sel = 'ua_info';
66775fa767dSAndreas Gohr        }
66875fa767dSAndreas Gohr
669bd4217d3SAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, $sel
67075fa767dSAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
67175fa767dSAndreas Gohr                 WHERE $tlimit
67275fa767dSAndreas Gohr                   AND ua_type = 'browser'
67375fa767dSAndreas Gohr              GROUP BY $grp
67475fa767dSAndreas Gohr              ORDER BY cnt DESC, ua_info".
67575fa767dSAndreas Gohr              $this->sql_limit($start,$limit);
67675fa767dSAndreas Gohr        return $this->runSQL($sql);
67775fa767dSAndreas Gohr    }
67875fa767dSAndreas Gohr
679bd4217d3SAndreas Gohr    function sql_os($tlimit,$start=0,$limit=20){
680bd4217d3SAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, os as osflag, os
681bd4217d3SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
682bd4217d3SAndreas Gohr                 WHERE $tlimit
683bd4217d3SAndreas Gohr                   AND ua_type = 'browser'
684bd4217d3SAndreas Gohr              GROUP BY os
685bd4217d3SAndreas Gohr              ORDER BY cnt DESC, os".
686bd4217d3SAndreas Gohr              $this->sql_limit($start,$limit);
687bd4217d3SAndreas Gohr        return $this->runSQL($sql);
688bd4217d3SAndreas Gohr    }
689bd4217d3SAndreas Gohr
690*c73e16f1SAndreas Gohr    function sql_resolution($tlimit,$start=0,$limit=20){
691*c73e16f1SAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, CONCAT(screen_x,'x',screen_y) as res
692*c73e16f1SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
693*c73e16f1SAndreas Gohr                 WHERE $tlimit
694*c73e16f1SAndreas Gohr                   AND ua_type  = 'browser'
695*c73e16f1SAndreas Gohr                   AND screen_x != 0
696*c73e16f1SAndreas Gohr              GROUP BY screen_x, screen_y
697*c73e16f1SAndreas Gohr              ORDER BY cnt DESC, screen_x".
698*c73e16f1SAndreas Gohr              $this->sql_limit($start,$limit);
699*c73e16f1SAndreas Gohr        return $this->runSQL($sql);
700*c73e16f1SAndreas Gohr    }
701*c73e16f1SAndreas Gohr
702*c73e16f1SAndreas Gohr    function sql_viewport($tlimit,$start=0,$limit=20,$x=true){
703*c73e16f1SAndreas Gohr        if($x){
704*c73e16f1SAndreas Gohr            $col = 'view_x';
705*c73e16f1SAndreas Gohr            $res = 'res_x';
706*c73e16f1SAndreas Gohr        }else{
707*c73e16f1SAndreas Gohr            $col = 'view_y';
708*c73e16f1SAndreas Gohr            $res = 'res_y';
709*c73e16f1SAndreas Gohr        }
710*c73e16f1SAndreas Gohr
711*c73e16f1SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt,
712*c73e16f1SAndreas Gohr                       ROUND($col/10)*10 as $res
713*c73e16f1SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."access as A
714*c73e16f1SAndreas Gohr                 WHERE $tlimit
715*c73e16f1SAndreas Gohr                   AND ua_type  = 'browser'
716*c73e16f1SAndreas Gohr                   AND $col != 0
717*c73e16f1SAndreas Gohr              GROUP BY $res
718*c73e16f1SAndreas Gohr              ORDER BY cnt DESC, $res".
719*c73e16f1SAndreas Gohr              $this->sql_limit($start,$limit);
720*c73e16f1SAndreas Gohr        return $this->runSQL($sql);
721*c73e16f1SAndreas Gohr    }
722*c73e16f1SAndreas Gohr
72375fa767dSAndreas Gohr
72495eb68e6SAndreas Gohr    /**
72595eb68e6SAndreas Gohr     * Builds a limit clause
72695eb68e6SAndreas Gohr     */
72795eb68e6SAndreas Gohr    function sql_limit($start,$limit){
72895eb68e6SAndreas Gohr        $start = (int) $start;
72995eb68e6SAndreas Gohr        $limit = (int) $limit;
73095eb68e6SAndreas Gohr        if($limit){
7312507f8e0SAndreas Gohr            $limit += 1;
73295eb68e6SAndreas Gohr            return " LIMIT $start,$limit";
73395eb68e6SAndreas Gohr        }elseif($start){
73495eb68e6SAndreas Gohr            return " OFFSET $start";
73595eb68e6SAndreas Gohr        }
73695eb68e6SAndreas Gohr        return '';
73795eb68e6SAndreas Gohr    }
7381878f16fSAndreas Gohr
7391878f16fSAndreas Gohr    /**
74014d99ec0SAndreas Gohr     * Return a link to the DB, opening the connection if needed
7411878f16fSAndreas Gohr     */
74214d99ec0SAndreas Gohr    function dbLink(){
7431878f16fSAndreas Gohr        // connect to DB if needed
7441878f16fSAndreas Gohr        if(!$this->dblink){
7451878f16fSAndreas Gohr            $this->dblink = mysql_connect($this->getConf('db_server'),
7461878f16fSAndreas Gohr                                          $this->getConf('db_user'),
7471878f16fSAndreas Gohr                                          $this->getConf('db_password'));
7481878f16fSAndreas Gohr            if(!$this->dblink){
7491878f16fSAndreas Gohr                msg('DB Error: connection failed',-1);
7501878f16fSAndreas Gohr                return null;
7511878f16fSAndreas Gohr            }
7521878f16fSAndreas Gohr            // set utf-8
7531878f16fSAndreas Gohr            if(!mysql_db_query($this->getConf('db_database'),'set names utf8',$this->dblink)){
7541878f16fSAndreas Gohr                msg('DB Error: could not set UTF-8 ('.mysql_error($this->dblink).')',-1);
7551878f16fSAndreas Gohr                return null;
7561878f16fSAndreas Gohr            }
7571878f16fSAndreas Gohr        }
75814d99ec0SAndreas Gohr        return $this->dblink;
75914d99ec0SAndreas Gohr    }
7601878f16fSAndreas Gohr
76114d99ec0SAndreas Gohr    /**
76214d99ec0SAndreas Gohr     * Simple function to run a DB query
76314d99ec0SAndreas Gohr     */
76414d99ec0SAndreas Gohr    function runSQL($sql_string) {
76514d99ec0SAndreas Gohr        $link = $this->dbLink();
76614d99ec0SAndreas Gohr
76714d99ec0SAndreas Gohr        $result = mysql_db_query($this->conf['db_database'],$sql_string,$link);
76894171ff3SAndreas Gohr        if(!$result){
7692812a751SAndreas Gohr            msg('DB Error: '.mysql_error($link).' '.hsc($sql_string),-1);
7701878f16fSAndreas Gohr            return null;
7711878f16fSAndreas Gohr        }
7721878f16fSAndreas Gohr
7731878f16fSAndreas Gohr        $resultarray = array();
7741878f16fSAndreas Gohr
7751878f16fSAndreas Gohr        //mysql_db_query returns 1 on a insert statement -> no need to ask for results
7761878f16fSAndreas Gohr        if ($result != 1) {
7771878f16fSAndreas Gohr            for($i=0; $i< mysql_num_rows($result); $i++) {
7781878f16fSAndreas Gohr                $temparray = mysql_fetch_assoc($result);
7791878f16fSAndreas Gohr                $resultarray[]=$temparray;
7801878f16fSAndreas Gohr            }
7811878f16fSAndreas Gohr            mysql_free_result($result);
7821878f16fSAndreas Gohr        }
7831878f16fSAndreas Gohr
78414d99ec0SAndreas Gohr        if (mysql_insert_id($link)) {
78514d99ec0SAndreas Gohr            $resultarray = mysql_insert_id($link); //give back ID on insert
7861878f16fSAndreas Gohr        }
7871878f16fSAndreas Gohr
7881878f16fSAndreas Gohr        return $resultarray;
7891878f16fSAndreas Gohr    }
7901878f16fSAndreas Gohr
7911878f16fSAndreas Gohr    /**
79214d99ec0SAndreas Gohr     * Returns a short name for a User Agent and sets type, version and os info
7931878f16fSAndreas Gohr     */
79414d99ec0SAndreas Gohr    function ua_info($ua,&$type,&$ver,&$os){
79514d99ec0SAndreas Gohr        $ua = strtr($ua,' +','__');
79614d99ec0SAndreas Gohr        $ua = strtolower($ua);
79714d99ec0SAndreas Gohr
79814d99ec0SAndreas Gohr        // common browsers
79914d99ec0SAndreas Gohr        $regvermsie     = '/msie([+_ ]|)([\d\.]*)/i';
80014d99ec0SAndreas Gohr        $regvernetscape = '/netscape.?\/([\d\.]*)/i';
80114d99ec0SAndreas Gohr        $regverfirefox  = '/firefox\/([\d\.]*)/i';
80214d99ec0SAndreas Gohr        $regversvn      = '/svn\/([\d\.]*)/i';
80314d99ec0SAndreas Gohr        $regvermozilla  = '/mozilla(\/|)([\d\.]*)/i';
80414d99ec0SAndreas Gohr        $regnotie       = '/webtv|omniweb|opera/i';
80514d99ec0SAndreas Gohr        $regnotnetscape = '/gecko|compatible|opera|galeon|safari/i';
80614d99ec0SAndreas Gohr
80714d99ec0SAndreas Gohr        $name = '';
80814d99ec0SAndreas Gohr        # IE ?
80914d99ec0SAndreas Gohr        if(preg_match($regvermsie,$ua,$m) && !preg_match($regnotie,$ua)){
81014d99ec0SAndreas Gohr            $type = 'browser';
81114d99ec0SAndreas Gohr            $ver  = $m[2];
81214d99ec0SAndreas Gohr            $name = 'msie';
81314d99ec0SAndreas Gohr        }
81414d99ec0SAndreas Gohr        # Firefox ?
81514d99ec0SAndreas Gohr        elseif (preg_match($regverfirefox,$ua,$m)){
81614d99ec0SAndreas Gohr            $type = 'browser';
81714d99ec0SAndreas Gohr            $ver  = $m[1];
81814d99ec0SAndreas Gohr            $name = 'firefox';
81914d99ec0SAndreas Gohr        }
82014d99ec0SAndreas Gohr        # Subversion ?
82114d99ec0SAndreas Gohr        elseif (preg_match($regversvn,$ua,$m)){
82214d99ec0SAndreas Gohr            $type = 'rcs';
82314d99ec0SAndreas Gohr            $ver  = $m[1];
82414d99ec0SAndreas Gohr            $name = 'svn';
82514d99ec0SAndreas Gohr        }
82614d99ec0SAndreas Gohr        # Netscape 6.x, 7.x ... ?
82714d99ec0SAndreas Gohr        elseif (preg_match($regvernetscape,$ua,$m)){
82814d99ec0SAndreas Gohr            $type = 'browser';
82914d99ec0SAndreas Gohr            $ver  = $m[1];
83014d99ec0SAndreas Gohr            $name = 'netscape';
83114d99ec0SAndreas Gohr        }
83214d99ec0SAndreas Gohr        # Netscape 3.x, 4.x ... ?
83314d99ec0SAndreas Gohr        elseif(preg_match($regvermozilla,$ua,$m) && !preg_match($regnotnetscape,$ua)){
83414d99ec0SAndreas Gohr            $type = 'browser';
83514d99ec0SAndreas Gohr            $ver  = $m[2];
83614d99ec0SAndreas Gohr            $name = 'netscape';
83714d99ec0SAndreas Gohr        }else{
83814d99ec0SAndreas Gohr            include(dirname(__FILE__).'/inc/browsers.php');
83914d99ec0SAndreas Gohr            foreach($BrowsersSearchIDOrder as $regex){
84014d99ec0SAndreas Gohr                if(preg_match('/'.$regex.'/',$ua)){
84114d99ec0SAndreas Gohr                    // it's a browser!
84214d99ec0SAndreas Gohr                    $type = 'browser';
84314d99ec0SAndreas Gohr                    $name = strtolower($regex);
84414d99ec0SAndreas Gohr                    break;
84514d99ec0SAndreas Gohr                }
84614d99ec0SAndreas Gohr            }
84714d99ec0SAndreas Gohr        }
84814d99ec0SAndreas Gohr
84975fa767dSAndreas Gohr        // check versions for Safari and Opera
85075fa767dSAndreas Gohr        if($name == 'safari'){
85175fa767dSAndreas Gohr            if(preg_match('/safari\/([\d\.]*)/i',$ua,$match)){
85275fa767dSAndreas Gohr                $ver = $BrowsersSafariBuildToVersionHash[$match[1]];
85375fa767dSAndreas Gohr            }
85475fa767dSAndreas Gohr        }elseif($name == 'opera'){
85575fa767dSAndreas Gohr            if(preg_match('/opera[\/ ]([\d\.]*)/i',$ua,$match)){
85675fa767dSAndreas Gohr                $ver = $match[1];
85775fa767dSAndreas Gohr            }
85875fa767dSAndreas Gohr        }
85975fa767dSAndreas Gohr
86075fa767dSAndreas Gohr
86114d99ec0SAndreas Gohr        // check OS for browsers
86214d99ec0SAndreas Gohr        if($type == 'browser'){
86314d99ec0SAndreas Gohr            include(dirname(__FILE__).'/inc/operating_systems.php');
86414d99ec0SAndreas Gohr            foreach($OSSearchIDOrder as $regex){
86514d99ec0SAndreas Gohr                if(preg_match('/'.$regex.'/',$ua)){
86614d99ec0SAndreas Gohr                    $os = $OSHashID[$regex];
86714d99ec0SAndreas Gohr                    break;
86814d99ec0SAndreas Gohr                }
86914d99ec0SAndreas Gohr            }
87014d99ec0SAndreas Gohr
87114d99ec0SAndreas Gohr        }
87214d99ec0SAndreas Gohr
87314d99ec0SAndreas Gohr        // are we done now?
87414d99ec0SAndreas Gohr        if($name) return $name;
87514d99ec0SAndreas Gohr
87614d99ec0SAndreas Gohr        include(dirname(__FILE__).'/inc/robots.php');
87714d99ec0SAndreas Gohr        foreach($RobotsSearchIDOrder as $regex){
87814d99ec0SAndreas Gohr            if(preg_match('/'.$regex.'/',$ua)){
87914d99ec0SAndreas Gohr                    // it's a robot!
88014d99ec0SAndreas Gohr                    $type = 'robot';
88114d99ec0SAndreas Gohr                    return strtolower($regex);
88214d99ec0SAndreas Gohr            }
88314d99ec0SAndreas Gohr        }
88414d99ec0SAndreas Gohr
88514d99ec0SAndreas Gohr        // dunno
8861878f16fSAndreas Gohr        return '';
8871878f16fSAndreas Gohr    }
8881878f16fSAndreas Gohr
8891878f16fSAndreas Gohr    /**
89014d99ec0SAndreas Gohr     *
89114d99ec0SAndreas Gohr     * @fixme: put search engine queries in seperate table here
89214d99ec0SAndreas Gohr     */
89314d99ec0SAndreas Gohr    function log_search($referer,&$type){
89414d99ec0SAndreas Gohr        $referer = strtr($referer,' +','__');
89514d99ec0SAndreas Gohr        $referer = strtolower($referer);
89614d99ec0SAndreas Gohr
89714d99ec0SAndreas Gohr        include(dirname(__FILE__).'/inc/search_engines.php');
89814d99ec0SAndreas Gohr
89914d99ec0SAndreas Gohr        foreach($SearchEnginesSearchIDOrder as $regex){
90014d99ec0SAndreas Gohr            if(preg_match('/'.$regex.'/',$referer)){
90114d99ec0SAndreas Gohr                if(!$NotSearchEnginesKeys[$regex] ||
90214d99ec0SAndreas Gohr                   !preg_match('/'.$NotSearchEnginesKeys[$regex].'/',$referer)){
90314d99ec0SAndreas Gohr                    // it's a search engine!
90414d99ec0SAndreas Gohr                    $type = 'search';
90514d99ec0SAndreas Gohr                    break;
90614d99ec0SAndreas Gohr                }
90714d99ec0SAndreas Gohr            }
90814d99ec0SAndreas Gohr        }
90914d99ec0SAndreas Gohr        if($type != 'search') return; // we're done here
91014d99ec0SAndreas Gohr
91114d99ec0SAndreas Gohr        #fixme now do the keyword magic!
91214d99ec0SAndreas Gohr    }
91314d99ec0SAndreas Gohr
91414d99ec0SAndreas Gohr    /**
91514d99ec0SAndreas Gohr     * Resolve IP to country/city
91614d99ec0SAndreas Gohr     */
91714d99ec0SAndreas Gohr    function log_ip($ip){
91814d99ec0SAndreas Gohr        // check if IP already known and up-to-date
91914d99ec0SAndreas Gohr        $sql = "SELECT ip
92014d99ec0SAndreas Gohr                  FROM ".$this->getConf('db_prefix')."iplocation
92114d99ec0SAndreas Gohr                 WHERE ip ='".addslashes($ip)."'
92214d99ec0SAndreas Gohr                   AND lastupd > DATE_SUB(CURDATE(),INTERVAL 30 DAY)";
92314d99ec0SAndreas Gohr        $result = $this->runSQL($sql);
92414d99ec0SAndreas Gohr        if($result[0]['ip']) return;
92514d99ec0SAndreas Gohr
92614d99ec0SAndreas Gohr        $http = new DokuHTTPClient();
92714d99ec0SAndreas Gohr        $http->timeout = 10;
92814d99ec0SAndreas Gohr        $data = $http->get('http://api.hostip.info/get_html.php?ip='.$ip);
92914d99ec0SAndreas Gohr
93014d99ec0SAndreas Gohr        if(preg_match('/^Country: (.*?) \((.*?)\)\nCity: (.*?)$/s',$data,$match)){
93114d99ec0SAndreas Gohr            $country = addslashes(trim($match[1]));
93214d99ec0SAndreas Gohr            $code    = addslashes(strtolower(trim($match[2])));
93314d99ec0SAndreas Gohr            $city    = addslashes(trim($match[3]));
93414d99ec0SAndreas Gohr            $host    = addslashes(gethostbyaddr($ip));
93514d99ec0SAndreas Gohr            $ip      = addslashes($ip);
93614d99ec0SAndreas Gohr
93714d99ec0SAndreas Gohr            $sql = "REPLACE INTO ".$this->getConf('db_prefix')."iplocation
93814d99ec0SAndreas Gohr                        SET ip = '$ip',
93914d99ec0SAndreas Gohr                            country = '$country',
94014d99ec0SAndreas Gohr                            code    = '$code',
94114d99ec0SAndreas Gohr                            city    = '$city',
94214d99ec0SAndreas Gohr                            host    = '$host'";
94314d99ec0SAndreas Gohr            $this->runSQL($sql);
94414d99ec0SAndreas Gohr        }
94514d99ec0SAndreas Gohr    }
94614d99ec0SAndreas Gohr
94714d99ec0SAndreas Gohr    /**
9481878f16fSAndreas Gohr     * log a page access
9491878f16fSAndreas Gohr     *
9501878f16fSAndreas Gohr     * called from log.php
9511878f16fSAndreas Gohr     */
9521878f16fSAndreas Gohr    function log_access(){
95394171ff3SAndreas Gohr        if(!$_REQUEST['p']) return;
95494171ff3SAndreas Gohr
95514d99ec0SAndreas Gohr        # FIXME check referer against blacklist and drop logging for bad boys
95614d99ec0SAndreas Gohr
95714d99ec0SAndreas Gohr        // handle referer
95814d99ec0SAndreas Gohr        $referer = trim($_REQUEST['r']);
95914d99ec0SAndreas Gohr        if($referer){
96014d99ec0SAndreas Gohr            $ref     = addslashes($referer);
96114d99ec0SAndreas Gohr            $ref_md5 = ($ref) ? md5($referer) : '';
96214d99ec0SAndreas Gohr            if(strpos($referer,DOKU_URL) === 0){
96314d99ec0SAndreas Gohr                $ref_type = 'internal';
96414d99ec0SAndreas Gohr            }else{
96514d99ec0SAndreas Gohr                $ref_type = 'external';
96614d99ec0SAndreas Gohr                $this->log_search($referer,$ref_type);
96714d99ec0SAndreas Gohr            }
96814d99ec0SAndreas Gohr        }else{
96914d99ec0SAndreas Gohr            $ref      = '';
97014d99ec0SAndreas Gohr            $ref_md5  = '';
97114d99ec0SAndreas Gohr            $ref_type = '';
97214d99ec0SAndreas Gohr        }
97314d99ec0SAndreas Gohr
97414d99ec0SAndreas Gohr        // handle user agent
97514d99ec0SAndreas Gohr        $agent   = trim($_SERVER['HTTP_USER_AGENT']);
97614d99ec0SAndreas Gohr
97714d99ec0SAndreas Gohr        $ua      = addslashes($agent);
97814d99ec0SAndreas Gohr        $ua_type = '';
97914d99ec0SAndreas Gohr        $ua_ver  = '';
98014d99ec0SAndreas Gohr        $os      = '';
98114d99ec0SAndreas Gohr        $ua_info = addslashes($this->ua_info($agent,$ua_type,$ua_ver,$os));
98214d99ec0SAndreas Gohr
9831878f16fSAndreas Gohr        $page    = addslashes($_REQUEST['p']);
9841878f16fSAndreas Gohr        $ip      = addslashes($_SERVER['REMOTE_ADDR']);
9851878f16fSAndreas Gohr        $sx      = (int) $_REQUEST['sx'];
9861878f16fSAndreas Gohr        $sy      = (int) $_REQUEST['sy'];
9871878f16fSAndreas Gohr        $vx      = (int) $_REQUEST['vx'];
9881878f16fSAndreas Gohr        $vy      = (int) $_REQUEST['vy'];
98975fa767dSAndreas Gohr        $js      = (int) $_REQUEST['js'];
9901878f16fSAndreas Gohr        $user    = addslashes($_SERVER['REMOTE_USER']);
9911878f16fSAndreas Gohr        $session = addslashes(session_id());
9921878f16fSAndreas Gohr
99394171ff3SAndreas Gohr        $sql  = "INSERT DELAYED INTO ".$this->getConf('db_prefix')."access
99475fa767dSAndreas Gohr                    SET dt       = NOW(),
99575fa767dSAndreas Gohr                        page     = '$page',
9961878f16fSAndreas Gohr                        ip       = '$ip',
9971878f16fSAndreas Gohr                        ua       = '$ua',
9981878f16fSAndreas Gohr                        ua_info  = '$ua_info',
99914d99ec0SAndreas Gohr                        ua_type  = '$ua_type',
100014d99ec0SAndreas Gohr                        ua_ver   = '$ua_ver',
100114d99ec0SAndreas Gohr                        os       = '$os',
10021878f16fSAndreas Gohr                        ref      = '$ref',
100394171ff3SAndreas Gohr                        ref_md5  = '$ref_md5',
100414d99ec0SAndreas Gohr                        ref_type = '$ref_type',
10051878f16fSAndreas Gohr                        screen_x = '$sx',
10061878f16fSAndreas Gohr                        screen_y = '$sy',
10071878f16fSAndreas Gohr                        view_x   = '$vx',
10081878f16fSAndreas Gohr                        view_y   = '$vy',
100975fa767dSAndreas Gohr                        js       = '$js',
10101878f16fSAndreas Gohr                        user     = '$user',
10111878f16fSAndreas Gohr                        session  = '$session'";
10121878f16fSAndreas Gohr        $ok = $this->runSQL($sql);
10131878f16fSAndreas Gohr        if(is_null($ok)){
10141878f16fSAndreas Gohr            global $MSG;
10151878f16fSAndreas Gohr            print_r($MSG);
10161878f16fSAndreas Gohr        }
101714d99ec0SAndreas Gohr
101814d99ec0SAndreas Gohr        // resolve the IP
101914d99ec0SAndreas Gohr        $this->log_ip($_SERVER['REMOTE_ADDR']);
10201878f16fSAndreas Gohr    }
10211878f16fSAndreas Gohr
10221878f16fSAndreas Gohr    /**
10231878f16fSAndreas Gohr     * Just send a 1x1 pixel blank gif to the browser
10241878f16fSAndreas Gohr     *
10251878f16fSAndreas Gohr     * @called from log.php
10261878f16fSAndreas Gohr     *
10271878f16fSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
10281878f16fSAndreas Gohr     * @author Harry Fuecks <fuecks@gmail.com>
10291878f16fSAndreas Gohr     */
10301878f16fSAndreas Gohr    function sendGIF(){
10311878f16fSAndreas Gohr        $img = base64_decode('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7');
10321878f16fSAndreas Gohr        header('Content-Type: image/gif');
10331878f16fSAndreas Gohr        header('Content-Length: '.strlen($img));
10341878f16fSAndreas Gohr        header('Connection: Close');
10351878f16fSAndreas Gohr        print $img;
10361878f16fSAndreas Gohr        flush();
10371878f16fSAndreas Gohr        // Browser should drop connection after this
10381878f16fSAndreas Gohr        // Thinks it's got the whole image
10391878f16fSAndreas Gohr    }
10401878f16fSAndreas Gohr
10411878f16fSAndreas Gohr}
1042