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