1<?php
2// must be run within Dokuwiki
3if(!defined('DOKU_INC')) die();
4
5/**
6 * statdisplay plugin table helper component
7 *
8 * @author Andreas Gohr <gohr@cosmocode.de>
9 * @license  GPL 2 (http://www.gnu.org/licenses/gpl.html)
10 */
11class helper_plugin_statdisplay_table extends DokuWiki_Plugin {
12    /** @var helper_plugin_statdisplay_log */
13    private $log = null;
14
15    /** @var Doku_Renderer */
16    private $R = null;
17
18    /**
19     * @param Doku_Renderer  $R
20     * @param string         $command  type of statistic
21     * @param string         $from     restrict to this month
22     * @param string         $to       end interval
23     * @return void
24     */
25    public function table($R, $command, $from = '', $to = '') {
26        $this->R   = $R;
27        $this->log = plugin_load('helper', 'statdisplay_log');
28
29        switch($command) {
30            case 'all':
31                $this->summary($from, $to);
32                break;
33            case 'one month':
34                $this->month($from);
35                break;
36            case 'month by day':
37                $this->monthby('day', $from);
38                break;
39            case 'month by hour':
40                $this->monthby('hour', $from);
41                break;
42            case 'top referers':
43                $this->referer($from);
44                break;
45            case 'top entries':
46                $this->entry($from);
47                break;
48            case 'top urls':
49                $this->url($from);
50                break;
51            case 'top bytes':
52                break;
53            case 'user agents':
54                $this->ua($from);
55                break;
56            case 'progress bar':
57                $this->progress();
58                break;
59            case 'traffic by user':
60                $this->userdownloads($from);
61                break;
62            default:
63                $R->cdata('No such table: '.$command);
64
65        }
66    }
67
68    private function progress() {
69        $pct = sprintf('%.2f', $this->log->progress());
70        $this->R->doc .= '<div class="statdisplay-progress" title="'.$pct.'%"><span style="width: '.$pct.'%"></span></div>';
71    }
72
73    /**
74     * Print referers for a given month
75     *
76     * @param string $date
77     */
78    private function referer($date = '') {
79        if(!$date) $date = date('Y-m');
80        $this->listtable(
81            $this->log->logdata[$date]['referer_url'],
82            $this->log->logdata[$date]['referer']['count'],
83            sprintf($this->getLang('t_topReferrer'), $date)
84        );
85    }
86
87    /**
88     * Print top entry pages for a given month
89     *
90     * @param string $date
91     */
92    private function entry($date = '') {
93        if(!$date) $date = date('Y-m');
94        $this->listtable(
95            $this->log->logdata[$date]['entry'],
96            $this->log->logdata[$date]['page']['all']['count'],
97            sprintf($this->getLang('t_topEntry'), $date)
98        );
99    }
100
101    /**
102     * Print top user agents for a given month
103     *
104     * @param string $date
105     */
106    private function ua($date = '') {
107        if(!$date) $date = date('Y-m');
108        $this->listtable(
109            $this->log->logdata[$date]['useragent'],
110            $this->log->logdata[$date]['page']['all']['count'],
111            sprintf($this->getLang('t_topUserAgents'), $date)
112        );
113    }
114
115    /**
116     * Print top pages for a given month
117     *
118     * @param string $date
119     */
120    private function url($date = '') {
121        if(!$date) $date = date('Y-m');
122        $this->listtable(
123            $this->log->logdata[$date]['page_url'],
124            $this->log->logdata[$date]['page']['all']['count'],
125            sprintf($this->getLang('t_topPages'), $date)
126        );
127    }
128
129    /**
130     * Print daily or hourly statistics
131     *
132     * @param string $by either 'day' or 'hour'
133     * @param string $date
134     */
135    private function monthby($by, $date = '') {
136        if(!$date) $date = date('Y-m');
137        $data = $this->log->logdata[$date];
138
139        $title = sprintf($this->getLang('t_'.$by), $date);
140
141        $this->R->table_open();
142
143        $this->R->tablerow_open();
144        $this->head($title, 11);
145        $this->R->tablerow_close();
146
147        $this->R->tablerow_open();
148        $this->head($this->getLang($by));
149        $this->head($this->getLang('hits'), 2);
150        $this->head($this->getLang('media'), 2);
151        $this->head($this->getLang('pages'), 2);
152        $this->head($this->getLang('visitors'), 2);
153        $this->head($this->getLang('traffic'), 2);
154        $this->R->tablerow_close();
155
156        foreach(array_keys((array) $data['hits'][$by]) as $idx) {
157            $this->R->tablerow_open();
158            $this->hcell($idx);
159
160            $this->cell($data['hits'][$by][$idx]['count']);
161            $this->cell($this->pct($data['hits'][$by][$idx]['count'], $data['hits']['all']['count']));
162
163            $this->cell($data['media'][$by][$idx]['count']);
164            $this->cell($this->pct($data['media'][$by][$idx]['count'], $data['media']['all']['count']));
165
166            $this->cell($data['page'][$by][$idx]['count']);
167            $this->cell($this->pct($data['page'][$by][$idx]['count'], $data['page']['all']['count']));
168
169            $this->cell($data['hits'][$by][$idx]['visitor']);
170            $this->cell($this->pct($data['hits'][$by][$idx]['visitor'], $data['hits']['all']['visitor']));
171
172            $this->cell(filesize_h($data['hits'][$by][$idx]['bytes']));
173            $this->cell($this->pct($data['hits'][$by][$idx]['bytes'], $data['hits']['all']['bytes']));
174
175            $this->R->tablerow_close();
176        }
177
178        $this->R->table_close();
179    }
180
181    /**
182     * print a single month
183     *
184     * @param $date
185     */
186    private function month($date = '') {
187        if(!$date) $date = date('Y-m');
188        $data = $this->log->logdata[$date];
189
190        $this->R->table_open();
191
192        $this->R->tablerow_open();
193        $this->head(sprintf($this->getLang('t_statisticMonth'), $date), 3);
194        $this->R->tablerow_close();
195
196        $this->R->tablerow_open();
197        $this->hcell($this->getLang('totalHits'));
198        $this->cell($data['page']['all']['count'] + $data['media']['all']['count'], 2);
199        $this->R->tablerow_close();
200
201        $this->R->tablerow_open();
202        $this->hcell($this->getLang('totalFiles'));
203        $this->cell($data['media']['all']['count'], 2);
204        $this->R->tablerow_close();
205
206        $this->R->tablerow_open();
207        $this->hcell($this->getLang('totalPages'));
208        $this->cell($data['page']['all']['count'], 2);
209        $this->R->tablerow_close();
210
211        $this->R->tablerow_open();
212        $this->hcell($this->getLang('totalVisitors'));
213        $this->cell($data['page']['all']['visitor'], 2);
214        $this->R->tablerow_close();
215
216        $this->R->tablerow_open();
217        $this->hcell($this->getLang('totalBytes'));
218        $this->cell(filesize_h($data['page']['all']['bytes']), 2);
219        $this->R->tablerow_close();
220
221        $this->R->tablerow_open();
222        $this->head('');
223        $this->head($this->getLang('avg'));
224        $this->head($this->getLang('max'));
225        $this->R->tablerow_close();
226
227        $this->R->tablerow_open();
228        $this->hcell($this->getLang('hitsHour'));
229        $this->cell($this->log->avg($data['hits']['hour'], 'count'));
230        $this->cell($this->log->max($data['hits']['hour'], 'count'));
231        $this->R->tablerow_close();
232
233        $this->R->tablerow_open();
234        $this->hcell($this->getLang('hitsDay'));
235        $this->cell($this->log->avg($data['hits']['day'], 'count'));
236        $this->cell($this->log->max($data['hits']['day'], 'count'));
237        $this->R->tablerow_close();
238
239        $this->R->tablerow_open();
240        $this->hcell($this->getLang('filesDay'));
241        $this->cell($this->log->avg($data['media']['day'], 'count'));
242        $this->cell($this->log->max($data['media']['day'], 'count'));
243        $this->R->tablerow_close();
244
245        $this->R->tablerow_open();
246        $this->hcell($this->getLang('pagesDay'));
247        $this->cell($this->log->avg($data['page']['day'], 'count'));
248        $this->cell($this->log->max($data['page']['day'], 'count'));
249        $this->R->tablerow_close();
250
251        $this->R->tablerow_open();
252        $this->hcell($this->getLang('bytesDay'));
253        $this->cell(filesize_h($this->log->avg($data['hits']['day'], 'bytes')));
254        $this->cell(filesize_h($this->log->max($data['hits']['day'], 'bytes')));
255        $this->R->tablerow_close();
256
257        $this->R->tablerow_open();
258        $this->head($this->getLang('hitsStatusCode'), 3);
259        $this->R->tablerow_close();
260
261        foreach((array) $this->log->logdata[$date]['status']['all'] as $code => $count) {
262            $this->R->tablerow_open();
263            $this->hcell('Status '.$code.' - '.$this->getLang('status_'.$code));
264            $this->cell($count, 2);
265            $this->R->tablerow_close();
266        }
267
268        $this->R->table_close();
269    }
270
271    /**
272     * print the whole summary table
273     */
274    private function summary($from = '', $to = '') {
275        $this->R->table_open();
276
277        $this->R->tablerow_open();
278        $this->head($this->getLang('summaryMonth'), 10);
279        $this->R->tablerow_close();
280
281        $this->R->tablerow_open();
282        $this->head($this->getLang('month'), 1, 2);
283        $this->head($this->getLang('dailyavg'), 4);
284        $this->head($this->getLang('totals'), 5);
285        $this->R->tablerow_close();
286
287        $this->R->tablerow_open();
288        $this->head($this->getLang('hits'));
289        $this->head($this->getLang('files'));
290        $this->head($this->getLang('pages'));
291        $this->head($this->getLang('visitors'));
292        $this->head($this->getLang('hits'));
293        $this->head($this->getLang('files'));
294        $this->head($this->getLang('pages'));
295        $this->head($this->getLang('visitors'));
296        $this->head($this->getLang('bytes'));
297
298        $this->R->tablerow_close();
299
300        foreach((array) $this->log->logdata as $month => $data) {
301            if($month{0} == '_') continue;
302            if($from && $month < $from) continue;
303            if($to && $month > $to) break;
304
305            $this->R->tablerow_open();
306
307            $this->cell($month, 1, false); // Month
308            // ---- averages ----
309            $this->cell(round($this->log->avg($data['hits']['day'], 'count'))); // Hits
310            $this->cell(round($this->log->avg($data['media']['day'], 'count'))); // Files
311            $this->cell(round($this->log->avg($data['page']['day'], 'count'))); // Pages
312            $this->cell(round($this->log->avg($data['hits']['day'], 'visitor'))); // Visits
313            // ---- totals ----
314            $this->cell($data['hits']['all']['count']); // Hits
315            $this->cell($data['media']['all']['count']); // Files
316            $this->cell($data['page']['all']['count']); // Pages
317            $this->cell($data['hits']['all']['visitor']); // Visitors
318            $this->cell(filesize_h($data['hits']['all']['bytes'])); // kBytes
319
320            $this->R->tablerow_close();
321        }
322
323        $this->R->table_close();
324    }
325
326    /**
327     * @param string $date month to display
328     */
329    private function userdownloads($date) {
330        $usertraffic = $this->log->usertraffic($date);
331
332        $this->listtable($usertraffic, $this->log->sum($usertraffic), $this->getLang('t_usertraffic'), true);
333    }
334
335    /**
336     * Print a simple listing table
337     *
338     * @param array  $data
339     * @param float  $max
340     * @param string $title
341     * @param bool   $istraffic
342     * @return void
343     */
344    private function listtable(&$data, $max, $title, $istraffic=false) {
345        if(!$data) $data = array();
346
347        arsort($data);
348        $row = 1;
349
350        $this->R->table_open();
351
352        $this->R->tablerow_open();
353        $this->head($title, 4);
354        $this->R->tablerow_close();
355
356        $this->R->tablerow_open();
357        $this->head('#');
358        $this->head($this->getLang('name'));
359        if($istraffic){
360            $this->head($this->getLang('traffic'), 2);
361        }else{
362            $this->head($this->getLang('hits'), 2);
363        }
364        $this->R->tablerow_close();
365
366        foreach($data as $key => $count) {
367            if($istraffic){
368                $val = filesize_h($count);
369            }else{
370                $val = $count;
371            }
372
373            $this->R->tablerow_open();
374            $this->cell($row);
375            $this->hcell($key);
376            $this->cell($val);
377            $this->cell($this->pct($count, $max));
378            $this->R->tablerow_close();
379            $row++;
380            if($row > $this->log->top_limit) break;
381        }
382
383        $this->R->table_close();
384    }
385
386    /**
387     * Calculate and format a percent value
388     *
389     * @param $val
390     * @param $max
391     * @return string
392     */
393    private function pct($val, $max) {
394        if(!$max) return '0.00%';
395
396        return sprintf("%.2f%%", $val * 100 / $max);
397    }
398
399    /**
400     * print a table header cell
401     *
402     * @param string $data
403     * @param int    $col
404     * @param int    $row
405     */
406    private function head($data = '', $col = 1, $row = 1) {
407        $this->R->tableheader_open($col, 'center', $row);
408        $this->R->cdata($data);
409        $this->R->tableheader_close();
410    }
411
412    /**
413     * print a non numeric data cell
414     *
415     * @param string $data
416     * @param int    $span
417     */
418    private function hcell($data = '', $span = 1) {
419        $this->cell($data, $span, false);
420    }
421
422    /**
423     * print a numeric data cell
424     *
425     * @param string $data
426     * @param int    $span
427     * @param bool   $number
428     */
429    private function cell($data = '', $span = 1, $number = true) {
430        if($number) {
431            if(!$data) $data = 0;
432            $align = 'right';
433        } else {
434            $align = null;
435        }
436
437        $this->R->tablecell_open($span, $align);
438        $this->R->cdata($data);
439        $this->R->tablecell_close();
440    }
441}
442