xref: /plugin/statistics/Query.php (revision 211caa5d3906ac05d560e9ce5a3171926bbb603c)
1b6632b6eSAndreas Gohr<?php
2b6632b6eSAndreas Gohr
3b6632b6eSAndreas Gohrnamespace dokuwiki\plugin\statistics;
4b6632b6eSAndreas Gohr
5f9e60319SAndreas Gohruse dokuwiki\plugin\sqlite\SQLiteDB;
6b6632b6eSAndreas Gohruse helper_plugin_statistics;
7b6632b6eSAndreas Gohr
8f9e60319SAndreas Gohr/**
9f9e60319SAndreas Gohr * This class defines a bunch of SQL queries to fetch various statistics from the database
10f9e60319SAndreas Gohr */
11b6632b6eSAndreas Gohrclass Query
12b6632b6eSAndreas Gohr{
13f9e60319SAndreas Gohr    protected helper_plugin_statistics $hlp;
14f9e60319SAndreas Gohr    protected SQLiteDB $db;
15f9e60319SAndreas Gohr    protected string $from;
16f9e60319SAndreas Gohr    protected string $to;
17f9e60319SAndreas Gohr    protected string $limit = '';
18b6632b6eSAndreas Gohr
19f9e60319SAndreas Gohr    /**
20f9e60319SAndreas Gohr     * @param helper_plugin_statistics $hlp
21f9e60319SAndreas Gohr     */
22b6632b6eSAndreas Gohr    public function __construct(helper_plugin_statistics $hlp)
23b6632b6eSAndreas Gohr    {
24b6632b6eSAndreas Gohr        $this->hlp = $hlp;
25f9e60319SAndreas Gohr        $this->db = $hlp->getDB();
267428e816SAndreas Gohr        $today = date('Y-m-d');
277428e816SAndreas Gohr        $this->setTimeFrame($today, $today);
28f9e60319SAndreas Gohr        $this->setPagination(0, 20);
297428e816SAndreas Gohr    }
307428e816SAndreas Gohr
317428e816SAndreas Gohr    /**
327428e816SAndreas Gohr     * Set the time frame for all queries
33f9e60319SAndreas Gohr     *
34f9e60319SAndreas Gohr     * @param string $from The start date as YYYY-MM-DD
35f9e60319SAndreas Gohr     * @param string $to The end date as YYYY-MM-DD
367428e816SAndreas Gohr     */
37f9e60319SAndreas Gohr    public function setTimeFrame(string $from, string $to): void
387428e816SAndreas Gohr    {
39f9e60319SAndreas Gohr        try {
40f9e60319SAndreas Gohr            $from = new \DateTime($from);
41f9e60319SAndreas Gohr            $to = new \DateTime($to);
42f9e60319SAndreas Gohr        } catch (\Exception $e) {
43f9e60319SAndreas Gohr            $from = new \DateTime();
44f9e60319SAndreas Gohr            $to = new \DateTime();
45f9e60319SAndreas Gohr        }
46f9e60319SAndreas Gohr        $from->setTime(0, 0);
47f9e60319SAndreas Gohr        $to->setTime(23, 59, 59);
487428e816SAndreas Gohr
49f9e60319SAndreas Gohr        $this->from = $from->format('Y-m-d H:i:s');
50f9e60319SAndreas Gohr        $this->to = $to->format('Y-m-d H:i:s');
51f9e60319SAndreas Gohr    }
52f9e60319SAndreas Gohr
53f9e60319SAndreas Gohr    /**
54f9e60319SAndreas Gohr     * Set the pagination settings for some queries
55f9e60319SAndreas Gohr     *
56f9e60319SAndreas Gohr     * @param int $start The start offset
57f9e60319SAndreas Gohr     * @param int $limit The number of results. If one more is returned, there is another page
58f9e60319SAndreas Gohr     * @return void
59f9e60319SAndreas Gohr     */
60f9e60319SAndreas Gohr    public function setPagination(int $start, int $limit)
61f9e60319SAndreas Gohr    {
62f9e60319SAndreas Gohr        // when a limit is set, one more is fetched to indicate when a next page exists
63f9e60319SAndreas Gohr        if ($limit) $limit += 1;
64f9e60319SAndreas Gohr
65f9e60319SAndreas Gohr        if ($limit) {
66f9e60319SAndreas Gohr            $this->limit = " LIMIT $start,$limit";
67f9e60319SAndreas Gohr        } elseif ($start) {
68f9e60319SAndreas Gohr            $this->limit = " OFFSET $start";
69f9e60319SAndreas Gohr        }
70b6632b6eSAndreas Gohr    }
71b6632b6eSAndreas Gohr
72b6632b6eSAndreas Gohr    /**
73b6632b6eSAndreas Gohr     * Return some aggregated statistics
74b6632b6eSAndreas Gohr     */
75f9e60319SAndreas Gohr    public function aggregate(): array
76b6632b6eSAndreas Gohr    {
77b6632b6eSAndreas Gohr        $data = [];
78b6632b6eSAndreas Gohr
79b6632b6eSAndreas Gohr        $sql = "SELECT ref_type, COUNT(*) as cnt
807428e816SAndreas Gohr                  FROM access as A
817428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
827428e816SAndreas Gohr                   AND ua_type = ?
83b6632b6eSAndreas Gohr              GROUP BY ref_type";
84f9e60319SAndreas Gohr        $result = $this->db->queryAll($sql, [$this->from, $this->to, 'browser']);
85b6632b6eSAndreas Gohr
86f9e60319SAndreas Gohr        foreach ($result as $row) {
87b6632b6eSAndreas Gohr            if ($row['ref_type'] == 'search') $data['search'] = $row['cnt'];
88b6632b6eSAndreas Gohr            if ($row['ref_type'] == 'external') $data['external'] = $row['cnt'];
89b6632b6eSAndreas Gohr            if ($row['ref_type'] == 'internal') $data['internal'] = $row['cnt'];
90b6632b6eSAndreas Gohr            if ($row['ref_type'] == '') $data['direct'] = $row['cnt'];
91b6632b6eSAndreas Gohr        }
92b6632b6eSAndreas Gohr
93b6632b6eSAndreas Gohr        // general user and session info
94b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as sessions,
95b6632b6eSAndreas Gohr                       COUNT(session) as views,
96b6632b6eSAndreas Gohr                       COUNT(DISTINCT user) as users,
97b6632b6eSAndreas Gohr                       COUNT(DISTINCT uid) as visitors
987428e816SAndreas Gohr                  FROM access as A
997428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
1007428e816SAndreas Gohr                   AND ua_type = ?";
101f9e60319SAndreas Gohr        $result = $this->db->queryRecord($sql, [$this->from, $this->to, 'browser']);
102b6632b6eSAndreas Gohr
103f9e60319SAndreas Gohr        $data['users'] = max($result['users'] - 1, 0); // subtract empty user
104f9e60319SAndreas Gohr        $data['sessions'] = $result['sessions'];
105f9e60319SAndreas Gohr        $data['pageviews'] = $result['views'];
106f9e60319SAndreas Gohr        $data['visitors'] = $result['visitors'];
107b6632b6eSAndreas Gohr
108b6632b6eSAndreas Gohr        // calculate bounce rate
109b6632b6eSAndreas Gohr        if ($data['sessions']) {
110b6632b6eSAndreas Gohr            $sql = "SELECT COUNT(*) as cnt
1117428e816SAndreas Gohr                      FROM session as A
1127428e816SAndreas Gohr                     WHERE A.dt >= ? AND A.dt <= ?
1137428e816SAndreas Gohr                       AND views = ?";
114f9e60319SAndreas Gohr            $count = $this->db->queryValue($sql, [$this->from, $this->to, 1]);
115f9e60319SAndreas Gohr            $data['bouncerate'] = $count * 100 / $data['sessions'];
116f9e60319SAndreas Gohr            $data['newvisitors'] = $count * 100 / $data['sessions'];
117b6632b6eSAndreas Gohr        }
118b6632b6eSAndreas Gohr
119b6632b6eSAndreas Gohr        // calculate avg. number of views per session
120b6632b6eSAndreas Gohr        $sql = "SELECT AVG(views) as cnt
1217428e816SAndreas Gohr                  FROM session as A
1227428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?";
123f9e60319SAndreas Gohr        $data['avgpages'] = $this->db->queryValue($sql, [$this->from, $this->to]);
124b6632b6eSAndreas Gohr
125b6632b6eSAndreas Gohr        // average time spent on the site
126b6632b6eSAndreas Gohr        $sql = "SELECT AVG(end - dt)/60 as time
1277428e816SAndreas Gohr                  FROM session as A
1287428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
129b6632b6eSAndreas Gohr                   AND dt != end
130b6632b6eSAndreas Gohr                   AND DATE(dt) = DATE(end)";
131f9e60319SAndreas Gohr        $data['timespent'] = $this->db->queryValue($sql, [$this->from, $this->to]);
132b6632b6eSAndreas Gohr
133b6632b6eSAndreas Gohr        // logins
134b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as logins
1357428e816SAndreas Gohr                  FROM logins as A
1367428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
1377428e816SAndreas Gohr                   AND (type = ? OR type = ?)";
138f9e60319SAndreas Gohr        $data['logins'] = $this->db->queryValue($sql, [$this->from, $this->to, 'l', 'p']);
139b6632b6eSAndreas Gohr
140b6632b6eSAndreas Gohr        // registrations
141b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as registrations
1427428e816SAndreas Gohr                  FROM logins as A
1437428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
1447428e816SAndreas Gohr                   AND type = ?";
145f9e60319SAndreas Gohr        $data['registrations'] = $this->db->queryValue($sql, [$this->from, $this->to, 'C']);
146b6632b6eSAndreas Gohr
147b6632b6eSAndreas Gohr        // current users
148b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as current
1497428e816SAndreas Gohr                  FROM lastseen
1507428e816SAndreas Gohr                 WHERE dt >= datetime('now', '-10 minutes')";
151f9e60319SAndreas Gohr        $data['current'] = $this->db->queryValue($sql);
152b6632b6eSAndreas Gohr
153b6632b6eSAndreas Gohr        return $data;
154b6632b6eSAndreas Gohr    }
155b6632b6eSAndreas Gohr
156b6632b6eSAndreas Gohr
157b6632b6eSAndreas Gohr    /**
158b6632b6eSAndreas Gohr     * Return some trend data about visits and edits in the wiki
159f9e60319SAndreas Gohr     *
160f9e60319SAndreas Gohr     * @param bool $hours Use hour resolution rather than days
161f9e60319SAndreas Gohr     * @return array
162b6632b6eSAndreas Gohr     */
163f9e60319SAndreas Gohr    public function dashboardviews(bool $hours = false): array
164b6632b6eSAndreas Gohr    {
165b6632b6eSAndreas Gohr        if ($hours) {
1667428e816SAndreas Gohr            $TIME = 'strftime(\'%H\', dt)';
167b6632b6eSAndreas Gohr        } else {
168b6632b6eSAndreas Gohr            $TIME = 'DATE(dt)';
169b6632b6eSAndreas Gohr        }
170b6632b6eSAndreas Gohr
171b6632b6eSAndreas Gohr        $data = [];
172b6632b6eSAndreas Gohr
173b6632b6eSAndreas Gohr        // access trends
174b6632b6eSAndreas Gohr        $sql = "SELECT $TIME as time,
175b6632b6eSAndreas Gohr                       COUNT(DISTINCT session) as sessions,
176b6632b6eSAndreas Gohr                       COUNT(session) as pageviews,
177b6632b6eSAndreas Gohr                       COUNT(DISTINCT uid) as visitors
1787428e816SAndreas Gohr                  FROM access as A
1797428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
1807428e816SAndreas Gohr                   AND ua_type = ?
181b6632b6eSAndreas Gohr              GROUP BY $TIME
182b6632b6eSAndreas Gohr              ORDER BY time";
183f9e60319SAndreas Gohr        $result = $this->db->queryAll($sql, [$this->from, $this->to, 'browser']);
184b6632b6eSAndreas Gohr        foreach ($result as $row) {
185b6632b6eSAndreas Gohr            $data[$row['time']]['sessions'] = $row['sessions'];
186b6632b6eSAndreas Gohr            $data[$row['time']]['pageviews'] = $row['pageviews'];
187b6632b6eSAndreas Gohr            $data[$row['time']]['visitors'] = $row['visitors'];
188b6632b6eSAndreas Gohr        }
189b6632b6eSAndreas Gohr        return $data;
190b6632b6eSAndreas Gohr    }
191b6632b6eSAndreas Gohr
192f9e60319SAndreas Gohr    /**
193f9e60319SAndreas Gohr     * @param bool $hours Use hour resolution rather than days
194f9e60319SAndreas Gohr     * @return array
195f9e60319SAndreas Gohr     */
196f9e60319SAndreas Gohr    public function dashboardwiki(bool $hours = false): array
197b6632b6eSAndreas Gohr    {
198b6632b6eSAndreas Gohr        if ($hours) {
1997428e816SAndreas Gohr            $TIME = 'strftime(\'%H\', dt)';
200b6632b6eSAndreas Gohr        } else {
201b6632b6eSAndreas Gohr            $TIME = 'DATE(dt)';
202b6632b6eSAndreas Gohr        }
203b6632b6eSAndreas Gohr
204b6632b6eSAndreas Gohr        $data = [];
205b6632b6eSAndreas Gohr
206b6632b6eSAndreas Gohr        // edit trends
207b6632b6eSAndreas Gohr        foreach (['E', 'C', 'D'] as $type) {
208b6632b6eSAndreas Gohr            $sql = "SELECT $TIME as time,
209b6632b6eSAndreas Gohr                           COUNT(*) as cnt
2107428e816SAndreas Gohr                      FROM edits as A
2117428e816SAndreas Gohr                     WHERE A.dt >= ? AND A.dt <= ?
2127428e816SAndreas Gohr                       AND type = ?
213b6632b6eSAndreas Gohr                  GROUP BY $TIME
214b6632b6eSAndreas Gohr                  ORDER BY time";
215f9e60319SAndreas Gohr            $result = $this->db->queryAll($sql, [$this->from, $this->to, $type]);
216b6632b6eSAndreas Gohr            foreach ($result as $row) {
217b6632b6eSAndreas Gohr                $data[$row['time']][$type] = $row['cnt'];
218b6632b6eSAndreas Gohr            }
219b6632b6eSAndreas Gohr        }
220b6632b6eSAndreas Gohr        ksort($data);
221b6632b6eSAndreas Gohr        return $data;
222b6632b6eSAndreas Gohr    }
223b6632b6eSAndreas Gohr
224f9e60319SAndreas Gohr    /**
225f9e60319SAndreas Gohr     * @param string $info Which type of history to select (FIXME which ones are there?)
226f9e60319SAndreas Gohr     * @param string $interval Group data by this interval (days, weeks, months)
227f9e60319SAndreas Gohr     * @return array
228f9e60319SAndreas Gohr     */
229f9e60319SAndreas Gohr    public function history(string $info, string $interval = 'day'): array
230b6632b6eSAndreas Gohr    {
231b6632b6eSAndreas Gohr        if ($interval == 'weeks') {
2327428e816SAndreas Gohr            $TIME = 'strftime(\'%Y\', dt), strftime(\'%W\', dt)';
233b6632b6eSAndreas Gohr        } elseif ($interval == 'months') {
2347428e816SAndreas Gohr            $TIME = 'strftime(\'%Y-%m\', dt)';
235b6632b6eSAndreas Gohr        } else {
236a087824eSAnna Dabrowska            $TIME = 'strftime(\'%d-%m\', dt)';
237b6632b6eSAndreas Gohr        }
238b6632b6eSAndreas Gohr
239b6632b6eSAndreas Gohr        $mod = 1;
240b6632b6eSAndreas Gohr        if ($info == 'media_size' || $info == 'page_size') {
241b6632b6eSAndreas Gohr            $mod = 1024 * 1024;
242b6632b6eSAndreas Gohr        }
243b6632b6eSAndreas Gohr
244b6632b6eSAndreas Gohr        $sql = "SELECT $TIME as time,
2457428e816SAndreas Gohr                       AVG(value)/$mod as cnt
2467428e816SAndreas Gohr                  FROM history as A
2477428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
2487428e816SAndreas Gohr                   AND info = ?
249b6632b6eSAndreas Gohr                  GROUP BY $TIME
250b6632b6eSAndreas Gohr                  ORDER BY $TIME";
251f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, $info]);
252b6632b6eSAndreas Gohr    }
253b6632b6eSAndreas Gohr
254f9e60319SAndreas Gohr    /**
255f9e60319SAndreas Gohr     * @return array
256f9e60319SAndreas Gohr     */
257f9e60319SAndreas Gohr    public function searchengines(): array
258b6632b6eSAndreas Gohr    {
259b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, engine as eflag, engine
2607428e816SAndreas Gohr                  FROM search as A
2617428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
262b6632b6eSAndreas Gohr              GROUP BY engine
263b6632b6eSAndreas Gohr              ORDER BY cnt DESC, engine" .
264f9e60319SAndreas Gohr            $this->limit;
265f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
266b6632b6eSAndreas Gohr    }
267b6632b6eSAndreas Gohr
268f9e60319SAndreas Gohr    /**
269f9e60319SAndreas Gohr     * @param bool $extern Limit results to external search engine (true) or dokuwiki (false)
270f9e60319SAndreas Gohr     * @return array
271f9e60319SAndreas Gohr     */
272*211caa5dSAndreas Gohr    public function searchphrases(bool $extern = false): array
273b6632b6eSAndreas Gohr    {
274b6632b6eSAndreas Gohr        if ($extern) {
2757428e816SAndreas Gohr            $WHERE = "engine != ?";
2767428e816SAndreas Gohr            $engineParam = 'dokuwiki';
277b6632b6eSAndreas Gohr            $I = '';
278b6632b6eSAndreas Gohr        } else {
2797428e816SAndreas Gohr            $WHERE = "engine = ?";
2807428e816SAndreas Gohr            $engineParam = 'dokuwiki';
281b6632b6eSAndreas Gohr            $I = 'i';
282b6632b6eSAndreas Gohr        }
283b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, query, query as ${I}lookup
2847428e816SAndreas Gohr                  FROM search as A
2857428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
286b6632b6eSAndreas Gohr                   AND $WHERE
287b6632b6eSAndreas Gohr              GROUP BY query
288b6632b6eSAndreas Gohr              ORDER BY cnt DESC, query" .
289f9e60319SAndreas Gohr            $this->limit;
290f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, $engineParam]);
291b6632b6eSAndreas Gohr    }
292b6632b6eSAndreas Gohr
293f9e60319SAndreas Gohr    /**
294f9e60319SAndreas Gohr     * @param bool $extern Limit results to external search engine (true) or dokuwiki (false)
295f9e60319SAndreas Gohr     * @return array
296f9e60319SAndreas Gohr     */
297*211caa5dSAndreas Gohr    public function searchwords(bool $extern = false): array
298b6632b6eSAndreas Gohr    {
299b6632b6eSAndreas Gohr        if ($extern) {
3007428e816SAndreas Gohr            $WHERE = "engine != ?";
3017428e816SAndreas Gohr            $engineParam = 'dokuwiki';
302b6632b6eSAndreas Gohr            $I = '';
303b6632b6eSAndreas Gohr        } else {
3047428e816SAndreas Gohr            $WHERE = "engine = ?";
3057428e816SAndreas Gohr            $engineParam = 'dokuwiki';
306b6632b6eSAndreas Gohr            $I = 'i';
307b6632b6eSAndreas Gohr        }
308b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, word, word as ${I}lookup
3097428e816SAndreas Gohr                  FROM search as A,
3107428e816SAndreas Gohr                       searchwords as B
3117428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
312b6632b6eSAndreas Gohr                   AND A.id = B.sid
313b6632b6eSAndreas Gohr                   AND $WHERE
314b6632b6eSAndreas Gohr              GROUP BY word
315b6632b6eSAndreas Gohr              ORDER BY cnt DESC, word" .
316f9e60319SAndreas Gohr            $this->limit;
317f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, $engineParam]);
318b6632b6eSAndreas Gohr    }
319b6632b6eSAndreas Gohr
320f9e60319SAndreas Gohr    /**
321f9e60319SAndreas Gohr     * @return array
322f9e60319SAndreas Gohr     */
323f9e60319SAndreas Gohr    public function outlinks(): array
324b6632b6eSAndreas Gohr    {
325b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, link as url
3267428e816SAndreas Gohr                  FROM outlinks as A
3277428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
328b6632b6eSAndreas Gohr              GROUP BY link
329b6632b6eSAndreas Gohr              ORDER BY cnt DESC, link" .
330f9e60319SAndreas Gohr            $this->limit;
331f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
332b6632b6eSAndreas Gohr    }
333b6632b6eSAndreas Gohr
334f9e60319SAndreas Gohr    /**
335f9e60319SAndreas Gohr     * @return array
336f9e60319SAndreas Gohr     */
337f9e60319SAndreas Gohr    public function pages(): array
338b6632b6eSAndreas Gohr    {
339b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, page
3407428e816SAndreas Gohr                  FROM access as A
3417428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
3427428e816SAndreas Gohr                   AND ua_type = ?
343b6632b6eSAndreas Gohr              GROUP BY page
344b6632b6eSAndreas Gohr              ORDER BY cnt DESC, page" .
345f9e60319SAndreas Gohr            $this->limit;
346f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'browser']);
347b6632b6eSAndreas Gohr    }
348b6632b6eSAndreas Gohr
349f9e60319SAndreas Gohr    /**
350f9e60319SAndreas Gohr     * @return array
351f9e60319SAndreas Gohr     */
352f9e60319SAndreas Gohr    public function edits(): array
353b6632b6eSAndreas Gohr    {
354b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, page
3557428e816SAndreas Gohr                  FROM edits as A
3567428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
357b6632b6eSAndreas Gohr              GROUP BY page
358b6632b6eSAndreas Gohr              ORDER BY cnt DESC, page" .
359f9e60319SAndreas Gohr            $this->limit;
360f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
361b6632b6eSAndreas Gohr    }
362b6632b6eSAndreas Gohr
363f9e60319SAndreas Gohr    /**
364f9e60319SAndreas Gohr     * @return array
365f9e60319SAndreas Gohr     */
366f9e60319SAndreas Gohr    public function images(): array
367b6632b6eSAndreas Gohr    {
368b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, media, SUM(size) as filesize
3697428e816SAndreas Gohr                  FROM media as A
3707428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
3717428e816SAndreas Gohr                   AND mime1 = ?
372b6632b6eSAndreas Gohr              GROUP BY media
373b6632b6eSAndreas Gohr              ORDER BY cnt DESC, media" .
374f9e60319SAndreas Gohr            $this->limit;
375f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'image']);
376b6632b6eSAndreas Gohr    }
377b6632b6eSAndreas Gohr
378f9e60319SAndreas Gohr    /**
379f9e60319SAndreas Gohr     * @return array
380f9e60319SAndreas Gohr     */
381f9e60319SAndreas Gohr    public function imagessum(): array
382b6632b6eSAndreas Gohr    {
383b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, SUM(size) as filesize
3847428e816SAndreas Gohr                  FROM media as A
3857428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
3867428e816SAndreas Gohr                   AND mime1 = ?";
387f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'image']);
388b6632b6eSAndreas Gohr    }
389b6632b6eSAndreas Gohr
390f9e60319SAndreas Gohr    /**
391f9e60319SAndreas Gohr     * @return array
392f9e60319SAndreas Gohr     */
393f9e60319SAndreas Gohr    public function downloads(): array
394b6632b6eSAndreas Gohr    {
395b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, media, SUM(size) as filesize
3967428e816SAndreas Gohr                  FROM media as A
3977428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
3987428e816SAndreas Gohr                   AND mime1 != ?
399b6632b6eSAndreas Gohr              GROUP BY media
400b6632b6eSAndreas Gohr              ORDER BY cnt DESC, media" .
401f9e60319SAndreas Gohr            $this->limit;
402f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'image']);
403b6632b6eSAndreas Gohr    }
404b6632b6eSAndreas Gohr
405f9e60319SAndreas Gohr    /**
406f9e60319SAndreas Gohr     * @return array
407f9e60319SAndreas Gohr     */
408f9e60319SAndreas Gohr    public function downloadssum(): array
409b6632b6eSAndreas Gohr    {
410b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, SUM(size) as filesize
4117428e816SAndreas Gohr                  FROM media as A
4127428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
4137428e816SAndreas Gohr                   AND mime1 != ?";
414f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'image']);
415b6632b6eSAndreas Gohr    }
416b6632b6eSAndreas Gohr
417f9e60319SAndreas Gohr    /**
418f9e60319SAndreas Gohr     * @return array
419f9e60319SAndreas Gohr     */
420f9e60319SAndreas Gohr    public function referer(): array
421b6632b6eSAndreas Gohr    {
422b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, ref as url
4237428e816SAndreas Gohr                  FROM access as A
4247428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
4257428e816SAndreas Gohr                   AND ua_type = ?
4267428e816SAndreas Gohr                   AND ref_type = ?
427b6632b6eSAndreas Gohr              GROUP BY ref_md5
428b6632b6eSAndreas Gohr              ORDER BY cnt DESC, url" .
429f9e60319SAndreas Gohr            $this->limit;
430f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'browser', 'external']);
431b6632b6eSAndreas Gohr    }
432b6632b6eSAndreas Gohr
433f9e60319SAndreas Gohr    /**
434f9e60319SAndreas Gohr     * @return array
435f9e60319SAndreas Gohr     */
436f9e60319SAndreas Gohr    public function newreferer(): array
437b6632b6eSAndreas Gohr    {
438b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, ref as url
4397428e816SAndreas Gohr                  FROM access as B,
4407428e816SAndreas Gohr                       refseen as A
4417428e816SAndreas Gohr                 WHERE B.dt >= ? AND B.dt <= ?
4427428e816SAndreas Gohr                   AND ua_type = ?
4437428e816SAndreas Gohr                   AND ref_type = ?
444b6632b6eSAndreas Gohr                   AND A.ref_md5 = B.ref_md5
445b6632b6eSAndreas Gohr              GROUP BY A.ref_md5
446b6632b6eSAndreas Gohr              ORDER BY cnt DESC, url" .
447f9e60319SAndreas Gohr            $this->limit;
448f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'browser', 'external']);
449b6632b6eSAndreas Gohr    }
450b6632b6eSAndreas Gohr
451f9e60319SAndreas Gohr    /**
452f9e60319SAndreas Gohr     * @return array
453f9e60319SAndreas Gohr     */
454f9e60319SAndreas Gohr    public function countries(): array
455b6632b6eSAndreas Gohr    {
456b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, B.code AS cflag, B.country
4577428e816SAndreas Gohr                  FROM access as A,
4587428e816SAndreas Gohr                       iplocation as B
4597428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
460b6632b6eSAndreas Gohr                   AND A.ip = B.ip
461b6632b6eSAndreas Gohr              GROUP BY B.code
462b6632b6eSAndreas Gohr              ORDER BY cnt DESC, B.country" .
463f9e60319SAndreas Gohr            $this->limit;
464f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
465b6632b6eSAndreas Gohr    }
466b6632b6eSAndreas Gohr
467f9e60319SAndreas Gohr    /**
468f9e60319SAndreas Gohr     * @param bool $ext return extended information
469f9e60319SAndreas Gohr     * @return array
470f9e60319SAndreas Gohr     */
471f9e60319SAndreas Gohr    public function browsers(bool $ext = true): array
472b6632b6eSAndreas Gohr    {
473b6632b6eSAndreas Gohr        if ($ext) {
474b6632b6eSAndreas Gohr            $sel = 'ua_info as bflag, ua_info as browser, ua_ver';
475b6632b6eSAndreas Gohr            $grp = 'ua_info, ua_ver';
476b6632b6eSAndreas Gohr        } else {
477b6632b6eSAndreas Gohr            $grp = 'ua_info';
478b6632b6eSAndreas Gohr            $sel = 'ua_info';
479b6632b6eSAndreas Gohr        }
480b6632b6eSAndreas Gohr
481b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, $sel
4827428e816SAndreas Gohr                  FROM access as A
4837428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
4847428e816SAndreas Gohr                   AND ua_type = ?
485b6632b6eSAndreas Gohr              GROUP BY $grp
486b6632b6eSAndreas Gohr              ORDER BY cnt DESC, ua_info" .
487f9e60319SAndreas Gohr            $this->limit;
488f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'browser']);
489b6632b6eSAndreas Gohr    }
490b6632b6eSAndreas Gohr
491f9e60319SAndreas Gohr    /**
492f9e60319SAndreas Gohr     * @return array
493f9e60319SAndreas Gohr     */
494f9e60319SAndreas Gohr    public function os(): array
495b6632b6eSAndreas Gohr    {
496b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT session) as cnt, os as osflag, os
4977428e816SAndreas Gohr                  FROM access as A
4987428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
4997428e816SAndreas Gohr                   AND ua_type = ?
500b6632b6eSAndreas Gohr              GROUP BY os
501b6632b6eSAndreas Gohr              ORDER BY cnt DESC, os" .
502f9e60319SAndreas Gohr            $this->limit;
503f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'browser']);
504b6632b6eSAndreas Gohr    }
505b6632b6eSAndreas Gohr
506f9e60319SAndreas Gohr    /**
507f9e60319SAndreas Gohr     * @return array
508f9e60319SAndreas Gohr     */
509f9e60319SAndreas Gohr    public function topuser(): array
510b6632b6eSAndreas Gohr    {
511b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, user
5127428e816SAndreas Gohr                  FROM access as A
5137428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
5147428e816SAndreas Gohr                   AND ua_type = ?
5157428e816SAndreas Gohr                   AND user != ?
516b6632b6eSAndreas Gohr              GROUP BY user
517b6632b6eSAndreas Gohr              ORDER BY cnt DESC, user" .
518f9e60319SAndreas Gohr            $this->limit;
519f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'browser', '']);
520b6632b6eSAndreas Gohr    }
521b6632b6eSAndreas Gohr
522f9e60319SAndreas Gohr    /**
523f9e60319SAndreas Gohr     * @return array
524f9e60319SAndreas Gohr     */
525f9e60319SAndreas Gohr    public function topeditor(): array
526b6632b6eSAndreas Gohr    {
527b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, user
5287428e816SAndreas Gohr                  FROM edits as A
5297428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
5307428e816SAndreas Gohr                   AND user != ?
531b6632b6eSAndreas Gohr              GROUP BY user
532b6632b6eSAndreas Gohr              ORDER BY cnt DESC, user" .
533f9e60319SAndreas Gohr            $this->limit;
534f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, '']);
535b6632b6eSAndreas Gohr    }
536b6632b6eSAndreas Gohr
537f9e60319SAndreas Gohr    /**
538f9e60319SAndreas Gohr     * @return array
539f9e60319SAndreas Gohr     */
540f9e60319SAndreas Gohr    public function topgroup(): array
541b6632b6eSAndreas Gohr    {
542b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, `group`
5437428e816SAndreas Gohr                  FROM groups as A
5447428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
5457428e816SAndreas Gohr                   AND `type` = ?
546b6632b6eSAndreas Gohr              GROUP BY `group`
547b6632b6eSAndreas Gohr              ORDER BY cnt DESC, `group`" .
548f9e60319SAndreas Gohr            $this->limit;
549f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'view']);
550b6632b6eSAndreas Gohr    }
551b6632b6eSAndreas Gohr
552f9e60319SAndreas Gohr    /**
553f9e60319SAndreas Gohr     * @return array
554f9e60319SAndreas Gohr     */
555f9e60319SAndreas Gohr    public function topgroupedit(): array
556b6632b6eSAndreas Gohr    {
557b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, `group`
5587428e816SAndreas Gohr                  FROM groups as A
5597428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
5607428e816SAndreas Gohr                   AND `type` = ?
561b6632b6eSAndreas Gohr              GROUP BY `group`
562b6632b6eSAndreas Gohr              ORDER BY cnt DESC, `group`" .
563f9e60319SAndreas Gohr            $this->limit;
564f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'edit']);
565b6632b6eSAndreas Gohr    }
566b6632b6eSAndreas Gohr
567b6632b6eSAndreas Gohr
568f9e60319SAndreas Gohr    /**
569f9e60319SAndreas Gohr     * @return array
570f9e60319SAndreas Gohr     */
571f9e60319SAndreas Gohr    public function resolution(): array
572b6632b6eSAndreas Gohr    {
573b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT uid) as cnt,
574b6632b6eSAndreas Gohr                       ROUND(screen_x/100)*100 as res_x,
575b6632b6eSAndreas Gohr                       ROUND(screen_y/100)*100 as res_y,
5767428e816SAndreas Gohr                       (ROUND(screen_x/100)*100 || 'x' || ROUND(screen_y/100)*100) as resolution
5777428e816SAndreas Gohr                  FROM access as A
5787428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
5797428e816SAndreas Gohr                   AND ua_type  = ?
5807428e816SAndreas Gohr                   AND screen_x != ?
5817428e816SAndreas Gohr                   AND screen_y != ?
582b6632b6eSAndreas Gohr              GROUP BY resolution
583b6632b6eSAndreas Gohr              ORDER BY cnt DESC" .
584f9e60319SAndreas Gohr            $this->limit;
585f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'browser', 0, 0]);
586b6632b6eSAndreas Gohr    }
587b6632b6eSAndreas Gohr
588f9e60319SAndreas Gohr    /**
589f9e60319SAndreas Gohr     * @return array
590f9e60319SAndreas Gohr     */
591f9e60319SAndreas Gohr    public function viewport(): array
592b6632b6eSAndreas Gohr    {
593b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT uid) as cnt,
594b6632b6eSAndreas Gohr                       ROUND(view_x/100)*100 as res_x,
595b6632b6eSAndreas Gohr                       ROUND(view_y/100)*100 as res_y,
5967428e816SAndreas Gohr                       (ROUND(view_x/100)*100 || 'x' || ROUND(view_y/100)*100) as resolution
5977428e816SAndreas Gohr                  FROM access as A
5987428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
5997428e816SAndreas Gohr                   AND ua_type  = ?
6007428e816SAndreas Gohr                   AND view_x != ?
6017428e816SAndreas Gohr                   AND view_y != ?
602b6632b6eSAndreas Gohr              GROUP BY resolution
603b6632b6eSAndreas Gohr              ORDER BY cnt DESC" .
604f9e60319SAndreas Gohr            $this->limit;
605b6632b6eSAndreas Gohr
606f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, 'browser', 0, 0]);
607b6632b6eSAndreas Gohr    }
608b6632b6eSAndreas Gohr
609f9e60319SAndreas Gohr    /**
610f9e60319SAndreas Gohr     * @return array
611f9e60319SAndreas Gohr     */
612f9e60319SAndreas Gohr    public function seenusers(): array
613b6632b6eSAndreas Gohr    {
614b6632b6eSAndreas Gohr        $sql = "SELECT `user`, `dt`
615*211caa5dSAndreas Gohr                  FROM lastseen as A
616b6632b6eSAndreas Gohr              ORDER BY `dt` DESC" .
617f9e60319SAndreas Gohr            $this->limit;
618b6632b6eSAndreas Gohr
619f9e60319SAndreas Gohr        return $this->db->queryAll($sql);
620b6632b6eSAndreas Gohr    }
621b6632b6eSAndreas Gohr}
622