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