xref: /plugin/statistics/admin.php (revision 33a136e585d9b9c249d5a6dafd7aae34974ee4c0)
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 * All DokuWiki plugins to extend the admin function
14 * need to inherit from this class
15 */
16class admin_plugin_statistics extends DokuWiki_Admin_Plugin {
17    /** @var string the currently selected page */
18    protected $opt = '';
19
20    /** @var string from date in YYYY-MM-DD */
21    protected $from = '';
22    /** @var string to date in YYYY-MM-DD */
23    protected $to = '';
24    /** @var int Offset to use when displaying paged data */
25    protected $start = 0;
26
27    /** @var string MySQL timelimit statement */
28    protected $tlimit = '';
29
30    /** @var helper_plugin_statistics  */
31    protected $hlp;
32
33    /**
34     * Available statistic pages
35     */
36    protected $pages = array(
37        'dashboard', 'page', 'referer', 'newreferer',
38        'outlinks', 'searchengines', 'searchphrases',
39        'searchwords', 'internalsearchphrases',
40        'internalsearchwords', 'browsers', 'os',
41        'countries', 'resolution', 'viewport',
42        'seenusers'
43    );
44
45    /**
46     * Initialize the helper
47     */
48    public function __construct() {
49        $this->hlp = plugin_load('helper', 'statistics');
50    }
51
52    /**
53     * Access for managers allowed
54     */
55    public function forAdminOnly() {
56        return false;
57    }
58
59    /**
60     * return sort order for position in admin menu
61     */
62    public function getMenuSort() {
63        return 350;
64    }
65
66    /**
67     * handle user request
68     */
69    public function handle() {
70        $this->opt = preg_replace('/[^a-z]+/', '', $_REQUEST['opt']);
71        if(!in_array($this->opt, $this->pages)) $this->opt = 'dashboard';
72
73        $this->start = (int) $_REQUEST['s'];
74        $this->setTimeframe($_REQUEST['f'], $_REQUEST['t']);
75    }
76
77    /**
78     * set limit clause
79     */
80    public function setTimeframe($from, $to) {
81        $this->tlimit = $this->hlp->Query()->mktlimit($from, $to);
82        $this->from   = $from;
83        $this->to     = $to;
84    }
85
86    /**
87     * Output the Statistics
88     */
89    function html() {
90        echo '<div id="plugin__statistics">';
91        echo '<h1>' . $this->getLang('menu') . '</h1>';
92        $this->html_timeselect();
93        tpl_flush();
94
95        $method = 'html_' . $this->opt;
96        if(method_exists($this, $method)) {
97            echo '<div class="plg_stats_' . $this->opt . '">';
98            echo '<h2>' . $this->getLang($this->opt) . '</h2>';
99            $this->$method();
100            echo '</div>';
101        }
102        echo '</div>';
103    }
104
105    /**
106     * Return the TOC
107     *
108     * @return array
109     */
110    function getTOC() {
111        $toc = array();
112        foreach($this->pages as $page) {
113            $toc[] = array(
114                'link'  => '?do=admin&amp;page=statistics&amp;opt=' . $page . '&amp;f=' . $this->from . '&amp;t=' . $this->to,
115                'title' => $this->getLang($page),
116                'level' => 1,
117                'type'  => 'ul'
118            );
119        }
120        return $toc;
121    }
122
123    function html_graph($name, $width, $height) {
124        $url = DOKU_BASE . 'lib/plugins/statistics/img.php?img=' . $name .
125            '&amp;f=' . $this->from . '&amp;t=' . $this->to;
126        echo '<img src="' . $url . '" class="graph" width="' . $width . '" height="' . $height . '"/>';
127    }
128
129    /**
130     * Outputs pagination links
131     *
132     * @param int $limit
133     * @param int $next
134     */
135    function html_pager($limit, $next) {
136        echo '<div class="plg_stats_pager">';
137
138        if($this->start > 0) {
139            $go = max($this->start - $limit, 0);
140            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 button">' . $this->getLang('prev') . '</a>';
141        }
142
143        if($next) {
144            $go = $this->start + $limit;
145            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 button">' . $this->getLang('next') . '</a>';
146        }
147        echo '</div>';
148    }
149
150    /**
151     * Print the time selection menu
152     */
153    function html_timeselect() {
154        $today  = date('Y-m-d');
155        $last1  = date('Y-m-d', time() - (60 * 60 * 24));
156        $last7  = date('Y-m-d', time() - (60 * 60 * 24 * 7));
157        $last30 = date('Y-m-d', time() - (60 * 60 * 24 * 30));
158
159        echo '<div class="plg_stats_timeselect">';
160        echo '<span>' . $this->getLang('time_select') . '</span> ';
161
162        echo '<form action="" method="get">';
163        echo '<input type="hidden" name="do" value="admin" />';
164        echo '<input type="hidden" name="page" value="statistics" />';
165        echo '<input type="hidden" name="opt" value="' . $this->opt . '" />';
166        echo '<input type="text" name="f" value="' . $this->from . '" class="edit" />';
167        echo '<input type="text" name="t" value="' . $this->to . '" class="edit" />';
168        echo '<input type="submit" value="go" class="button" />';
169        echo '</form>';
170
171        echo '<ul>';
172        foreach(array('today', 'last1', 'last7', 'last30') as $time) {
173            echo '<li>';
174            echo '<a href="?do=admin&amp;page=statistics&amp;opt=' . $this->opt . '&amp;f=' . $$time . '&amp;t=' . $today . '">';
175            echo $this->getLang('time_' . $time);
176            echo '</a>';
177            echo '</li>';
178        }
179        echo '</ul>';
180
181        echo '</div>';
182    }
183
184    /**
185     * Print an introductionary screen
186     */
187    function html_dashboard() {
188        echo '<p>' . $this->getLang('intro_dashboard') . '</p>';
189
190        // general info
191        echo '<div class="plg_stats_top">';
192        $result = $this->hlp->Query()->aggregate($this->tlimit);
193
194        echo '<ul class="left">';
195        foreach(array('pageviews', 'sessions', 'visitors', 'users', 'logins', 'current') as $name) {
196            echo '<li><div class="li">' . sprintf($this->getLang('dash_' . $name), $result[$name]) . '</div></li>';
197        }
198        echo '</ul>';
199
200        echo '<ul class="left">';
201        foreach(array('bouncerate', 'timespent', 'avgpages', 'newvisitors', 'registrations') as $name) {
202            echo '<li><div class="li">' . sprintf($this->getLang('dash_' . $name), $result[$name]) . '</div></li>';
203        }
204        echo '</ul>';
205
206        $this->html_graph('dashboardviews', 700, 280);
207        $this->html_graph('dashboardwiki', 700, 280);
208        echo '</div>';
209
210        // top pages today
211        echo '<div>';
212        echo '<h2>' . $this->getLang('dash_mostpopular') . '</h2>';
213        $result = $this->hlp->Query()->pages($this->tlimit, $this->start, 15);
214        $this->html_resulttable($result);
215        echo '<a href="?do=admin&amp;page=statistics&amp;opt=page&amp;f=' . $this->from . '&amp;t=' . $this->to . '" class="more button">' . $this->getLang('more') . '</a>';
216        echo '</div>';
217
218        // top referer today
219        echo '<div>';
220        echo '<h2>' . $this->getLang('dash_newincoming') . '</h2>';
221        $result = $this->hlp->Query()->newreferer($this->tlimit, $this->start, 15);
222        $this->html_resulttable($result);
223        echo '<a href="?do=admin&amp;page=statistics&amp;opt=newreferer&amp;f=' . $this->from . '&amp;t=' . $this->to . '" class="more button">' . $this->getLang('more') . '</a>';
224        echo '</div>';
225
226        // top searches today
227        echo '<div>';
228        echo '<h2>' . $this->getLang('dash_topsearch') . '</h2>';
229        $result = $this->hlp->Query()->searchphrases(true, $this->tlimit, $this->start, 15);
230        $this->html_resulttable($result);
231        echo '<a href="?do=admin&amp;page=statistics&amp;opt=searchphrases&amp;f=' . $this->from . '&amp;t=' . $this->to . '" class="more button">' . $this->getLang('more') . '</a>';
232        echo '</div>';
233    }
234
235    function html_countries() {
236        echo '<p>' . $this->getLang('intro_countries') . '</p>';
237        $this->html_graph('countries', 400, 200);
238        $result = $this->hlp->Query()->countries($this->tlimit, $this->start, 150);
239        $this->html_resulttable($result, '', 150);
240    }
241
242    function html_page() {
243        echo '<p>' . $this->getLang('intro_page') . '</p>';
244        $result = $this->hlp->Query()->pages($this->tlimit, $this->start, 150);
245        $this->html_resulttable($result, '', 150);
246    }
247
248    function html_browsers() {
249        echo '<p>' . $this->getLang('intro_browsers') . '</p>';
250        $this->html_graph('browsers', 400, 200);
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        echo '<p>' . $this->getLang('intro_os') . '</p>';
257        $this->html_graph('os', 400, 200);
258        $result = $this->hlp->Query()->os($this->tlimit, $this->start, 150, true);
259        $this->html_resulttable($result, '', 150);
260    }
261
262    function html_referer() {
263        $result = $this->hlp->Query()->aggregate($this->tlimit);
264
265        $all = $result['search'] + $result['external'] + $result['direct'];
266
267        if($all) {
268            printf(
269                '<p>' . $this->getLang('intro_referer') . '</p>',
270                $all, $result['direct'], (100 * $result['direct'] / $all),
271                $result['search'], (100 * $result['search'] / $all), $result['external'],
272                (100 * $result['external'] / $all)
273            );
274        }
275
276        $result = $this->hlp->Query()->referer($this->tlimit, $this->start, 150);
277        $this->html_resulttable($result, '', 150);
278    }
279
280    function html_newreferer() {
281        echo '<p>' . $this->getLang('intro_newreferer') . '</p>';
282
283        $result = $this->hlp->Query()->newreferer($this->tlimit, $this->start, 150);
284        $this->html_resulttable($result, '', 150);
285    }
286
287    function html_outlinks() {
288        echo '<p>' . $this->getLang('intro_outlinks') . '</p>';
289        $result = $this->hlp->Query()->outlinks($this->tlimit, $this->start, 150);
290        $this->html_resulttable($result, '', 150);
291    }
292
293    function html_searchphrases() {
294        echo '<p>' . $this->getLang('intro_searchphrases') . '</p>';
295        $result = $this->hlp->Query()->searchphrases(true, $this->tlimit, $this->start, 150);
296        $this->html_resulttable($result, '', 150);
297    }
298
299    function html_searchwords() {
300        echo '<p>' . $this->getLang('intro_searchwords') . '</p>';
301        $result = $this->hlp->Query()->searchwords(true, $this->tlimit, $this->start, 150);
302        $this->html_resulttable($result, '', 150);
303    }
304
305    function html_internalsearchphrases() {
306        echo '<p>' . $this->getLang('intro_internalsearchphrases') . '</p>';
307        $result = $this->hlp->Query()->searchphrases(false, $this->tlimit, $this->start, 150);
308        $this->html_resulttable($result, '', 150);
309    }
310
311    function html_internalsearchwords() {
312        echo '<p>' . $this->getLang('intro_internalsearchwords') . '</p>';
313        $result = $this->hlp->Query()->searchwords(false, $this->tlimit, $this->start, 150);
314        $this->html_resulttable($result, '', 150);
315    }
316
317    function html_searchengines() {
318        echo '<p>' . $this->getLang('intro_searchengines') . '</p>';
319        $this->html_graph('searchengines', 400, 200);
320        $result = $this->hlp->Query()->searchengines($this->tlimit, $this->start, 150);
321        $this->html_resulttable($result, '', 150);
322    }
323
324    function html_resolution() {
325        echo '<p>' . $this->getLang('intro_resolution') . '</p>';
326        $this->html_graph('resolution', 650, 490);
327        $result = $this->hlp->Query()->resolution($this->tlimit, $this->start, 150);
328        $this->html_resulttable($result, '', 150);
329    }
330
331    function html_viewport() {
332        echo '<p>' . $this->getLang('intro_viewport') . '</p>';
333        $this->html_graph('viewport', 650, 490);
334        $result = $this->hlp->Query()->viewport($this->tlimit, $this->start, 150);
335        $this->html_resulttable($result, '', 150);
336    }
337
338    function html_seenusers() {
339        echo '<p>' . $this->getLang('intro_seenusers') . '</p>';
340        $result = $this->hlp->Query()->seenusers($this->tlimit, $this->start, 150);
341        $this->html_resulttable($result, '', 150);
342    }
343
344    /**
345     * Display a result in a HTML table
346     */
347    function html_resulttable($result, $header = '', $pager = 0) {
348        echo '<table>';
349        if(is_array($header)) {
350            echo '<tr>';
351            foreach($header as $h) {
352                echo '<th>' . hsc($h) . '</th>';
353            }
354            echo '</tr>';
355        }
356
357        $count = 0;
358        if(is_array($result)) foreach($result as $row) {
359            echo '<tr>';
360            foreach($row as $k => $v) {
361                if($k == 'res_x') continue;
362                if($k == 'res_y') continue;
363
364                echo '<td class="plg_stats_X' . $k . '">';
365                if($k == 'page') {
366                    echo '<a href="' . wl($v) . '" class="wikilink1">';
367                    echo hsc($v);
368                    echo '</a>';
369                } elseif($k == 'url') {
370                    $url = hsc($v);
371                    $url = preg_replace('/^https?:\/\/(www\.)?/', '', $url);
372                    if(strlen($url) > 45) {
373                        $url = substr($url, 0, 30) . ' &hellip; ' . substr($url, -15);
374                    }
375                    echo '<a href="' . $v . '" class="urlextern">';
376                    echo $url;
377                    echo '</a>';
378                } elseif($k == 'ilookup') {
379                    echo '<a href="' . wl('', array('id' => $v, 'do' => 'search')) . '">Search</a>';
380                } elseif($k == 'lookup') {
381                    echo '<a href="http://www.google.com/search?q=' . rawurlencode($v) . '">';
382                    echo '<img src="' . DOKU_BASE . 'lib/plugins/statistics/ico/search/google.png" alt="Google" border="0" />';
383                    echo '</a> ';
384
385                    echo '<a href="http://search.yahoo.com/search?p=' . rawurlencode($v) . '">';
386                    echo '<img src="' . DOKU_BASE . 'lib/plugins/statistics/ico/search/yahoo.png" alt="Yahoo!" border="0" />';
387                    echo '</a> ';
388
389                    echo '<a href="http://www.bing.com/search?q=' . rawurlencode($v) . '">';
390                    echo '<img src="' . DOKU_BASE . 'lib/plugins/statistics/ico/search/bing.png" alt="Bing" border="0" />';
391                    echo '</a> ';
392
393                } elseif($k == 'engine') {
394                    include_once(dirname(__FILE__) . '/inc/searchengines.php');
395                    if(isset($SEARCHENGINEINFO[$v])) {
396                        echo '<a href="' . $SEARCHENGINEINFO[$v][1] . '">' . $SEARCHENGINEINFO[$v][0] . '</a>';
397                    } else {
398                        echo hsc(ucwords($v));
399                    }
400                } elseif($k == 'eflag') {
401                    $this->html_icon('search', $v);
402                } elseif($k == 'bflag') {
403                    $this->html_icon('browser', $v);
404                } elseif($k == 'osflag') {
405                    $this->html_icon('os', $v);
406                } elseif($k == 'cflag') {
407                    $this->html_icon('flags', $v);
408                } elseif($k == 'html') {
409                    echo $v;
410                } else {
411                    echo hsc($v);
412                }
413                echo '</td>';
414            }
415            echo '</tr>';
416
417            if($pager && ($count == $pager)) break;
418            $count++;
419        }
420        echo '</table>';
421
422        if($pager) $this->html_pager($pager, count($result) > $pager);
423    }
424
425    function html_icon($type, $value) {
426        $value = strtolower(preg_replace('/[^\w]+/', '', $value));
427        $value = str_replace(' ', '_', $value);
428        $file  = 'lib/plugins/statistics/ico/' . $type . '/' . $value . '.png';
429        if($type == 'flags') {
430            $w = 18;
431            $h = 12;
432        } else {
433            $w = 16;
434            $h = 16;
435        }
436        if(file_exists(DOKU_INC . $file)) {
437            echo '<img src="' . DOKU_BASE . $file . '" alt="' . hsc($value) . '" width="' . $w . '" height="' . $h . '" />';
438        }
439    }
440}
441