xref: /plugin/statistics/Query.php (revision 30cf9434862e9e86ae8734948e2dfc4f96e9cb10)
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    {
772a30f557SAndreas Gohr        // init some values that might not be set
782a30f557SAndreas Gohr        $data = [
792a30f557SAndreas Gohr            'referers' => 0, // total number of (external) referrers
802a30f557SAndreas Gohr            'external' => 0, // external referrers
812a30f557SAndreas Gohr            'search' => 0, // search engine referrers
822a30f557SAndreas Gohr            'direct' => 0, // direct referrers
832a30f557SAndreas Gohr            'internal' => 0, // internal referrers
842a30f557SAndreas Gohr            'bouncerate' => 0,
852a30f557SAndreas Gohr            'newvisitors' => 0,
862a30f557SAndreas Gohr        ];
87b6632b6eSAndreas Gohr
8810dcb86fSAndreas Gohr        // Count referrer types by joining with referers table
8910dcb86fSAndreas Gohr        $sql = "SELECT
9010dcb86fSAndreas Gohr                    CASE
9110dcb86fSAndreas Gohr                        WHEN R.engine IS NOT NULL THEN 'search'
922a30f557SAndreas Gohr                        WHEN R.url = '' THEN 'direct'
932a30f557SAndreas Gohr                        WHEN R.url IS NOT NULL THEN 'external'
942a30f557SAndreas Gohr                        ELSE 'internal'
9510dcb86fSAndreas Gohr                    END as ref_type,
9610dcb86fSAndreas Gohr                    COUNT(*) as cnt
9710dcb86fSAndreas Gohr                  FROM pageviews as P
9810dcb86fSAndreas Gohr                  LEFT JOIN referers as R ON P.ref_id = R.id
9910dcb86fSAndreas Gohr                  LEFT JOIN sessions as S ON P.session = S.session
10010dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
101*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
102b6632b6eSAndreas Gohr              GROUP BY ref_type";
103*30cf9434SAndreas Gohr        $result = $this->db->queryAll($sql, [$this->from, $this->to]);
104b6632b6eSAndreas Gohr
105f9e60319SAndreas Gohr        foreach ($result as $row) {
1062a30f557SAndreas Gohr            if ($row['ref_type'] == 'search') {
1072a30f557SAndreas Gohr                $data['search'] = $row['cnt'];
1082a30f557SAndreas Gohr                $data['referers'] += $row['cnt'];
1092a30f557SAndreas Gohr            }
1102a30f557SAndreas Gohr            if ($row['ref_type'] == 'direct') {
1112a30f557SAndreas Gohr                $data['direct'] = $row['cnt'];
1122a30f557SAndreas Gohr                $data['referers'] += $row['cnt'];
1132a30f557SAndreas Gohr            }
1142a30f557SAndreas Gohr            if ($row['ref_type'] == 'external') {
1152a30f557SAndreas Gohr                $data['external'] = $row['cnt'];
1162a30f557SAndreas Gohr                $data['referers'] += $row['cnt'];
1172a30f557SAndreas Gohr            }
1182a30f557SAndreas Gohr            if ($row['ref_type'] == 'internal') {
1192a30f557SAndreas Gohr                $data['internal'] = $row['cnt'];
1202a30f557SAndreas Gohr            }
121b6632b6eSAndreas Gohr        }
122b6632b6eSAndreas Gohr
123b6632b6eSAndreas Gohr        // general user and session info
12410dcb86fSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT P.session) as sessions,
12510dcb86fSAndreas Gohr                       COUNT(P.session) as views,
12610dcb86fSAndreas Gohr                       COUNT(DISTINCT S.user) as users,
12710dcb86fSAndreas Gohr                       COUNT(DISTINCT S.uid) as visitors
12810dcb86fSAndreas Gohr                  FROM pageviews as P
12910dcb86fSAndreas Gohr                  LEFT JOIN sessions as S ON P.session = S.session
13010dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
131*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'";
132*30cf9434SAndreas Gohr        $result = $this->db->queryRecord($sql, [$this->from, $this->to]);
133b6632b6eSAndreas Gohr
13410dcb86fSAndreas Gohr        $data['users'] = $result['users'];
135f9e60319SAndreas Gohr        $data['sessions'] = $result['sessions'];
136f9e60319SAndreas Gohr        $data['pageviews'] = $result['views'];
137f9e60319SAndreas Gohr        $data['visitors'] = $result['visitors'];
138b6632b6eSAndreas Gohr
13910dcb86fSAndreas Gohr        // calculate bounce rate (sessions with only 1 page view)
140b6632b6eSAndreas Gohr        if ($data['sessions']) {
141b6632b6eSAndreas Gohr            $sql = "SELECT COUNT(*) as cnt
14210dcb86fSAndreas Gohr                      FROM (
14310dcb86fSAndreas Gohr                          SELECT P.session, COUNT(*) as views
14410dcb86fSAndreas Gohr                            FROM pageviews as P
14510dcb86fSAndreas Gohr                            LEFT JOIN sessions as S ON P.session = S.session
14610dcb86fSAndreas Gohr                           WHERE P.dt >= ? AND P.dt <= ?
147*30cf9434SAndreas Gohr                             AND S.ua_type = 'browser'
14810dcb86fSAndreas Gohr                        GROUP BY P.session
14910dcb86fSAndreas Gohr                          HAVING views = 1
15010dcb86fSAndreas Gohr                      )";
151*30cf9434SAndreas Gohr            $count = $this->db->queryValue($sql, [$this->from, $this->to]);
152f9e60319SAndreas Gohr            $data['bouncerate'] = $count * 100 / $data['sessions'];
153f9e60319SAndreas Gohr            $data['newvisitors'] = $count * 100 / $data['sessions'];
154b6632b6eSAndreas Gohr        }
155b6632b6eSAndreas Gohr
156b6632b6eSAndreas Gohr        // calculate avg. number of views per session
157b6632b6eSAndreas Gohr        $sql = "SELECT AVG(views) as cnt
15810dcb86fSAndreas Gohr                  FROM (
15910dcb86fSAndreas Gohr                      SELECT P.session, COUNT(*) as views
16010dcb86fSAndreas Gohr                        FROM pageviews as P
16110dcb86fSAndreas Gohr                        LEFT JOIN sessions as S ON P.session = S.session
16210dcb86fSAndreas Gohr                       WHERE P.dt >= ? AND P.dt <= ?
163*30cf9434SAndreas Gohr                         AND S.ua_type = 'browser'
16410dcb86fSAndreas Gohr                    GROUP BY P.session
16510dcb86fSAndreas Gohr                  )";
166*30cf9434SAndreas Gohr        $data['avgpages'] = $this->db->queryValue($sql, [$this->from, $this->to]);
167b6632b6eSAndreas Gohr
168b6632b6eSAndreas Gohr        // average time spent on the site
16910dcb86fSAndreas Gohr        $sql = "SELECT AVG((julianday(end) - julianday(dt)) * 24 * 60) as time
17010dcb86fSAndreas Gohr                  FROM sessions as S
17110dcb86fSAndreas Gohr                 WHERE S.dt >= ? AND S.dt <= ?
17210dcb86fSAndreas Gohr                   AND S.dt != S.end
17310dcb86fSAndreas Gohr                   AND DATE(S.dt) = DATE(S.end)
174*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'";
175*30cf9434SAndreas Gohr        $data['timespent'] = $this->db->queryValue($sql, [$this->from, $this->to]);
176b6632b6eSAndreas Gohr
177b6632b6eSAndreas Gohr        // logins
178b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as logins
1797428e816SAndreas Gohr                  FROM logins as A
1807428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
181*30cf9434SAndreas Gohr                   AND (type = 'l' OR type = 'p')";
182*30cf9434SAndreas Gohr        $data['logins'] = $this->db->queryValue($sql, [$this->from, $this->to]);
183b6632b6eSAndreas Gohr
184b6632b6eSAndreas Gohr        // registrations
185b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as registrations
1867428e816SAndreas Gohr                  FROM logins as A
1877428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
188*30cf9434SAndreas Gohr                   AND type = 'C'";
189*30cf9434SAndreas Gohr        $data['registrations'] = $this->db->queryValue($sql, [$this->from, $this->to]);
190b6632b6eSAndreas Gohr
19110dcb86fSAndreas Gohr        // current users (based on recent sessions)
19210dcb86fSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT uid) as current
19310dcb86fSAndreas Gohr                  FROM sessions
19410dcb86fSAndreas Gohr                 WHERE end >= datetime('now', '-10 minutes')";
195f9e60319SAndreas Gohr        $data['current'] = $this->db->queryValue($sql);
196b6632b6eSAndreas Gohr
197b6632b6eSAndreas Gohr        return $data;
198b6632b6eSAndreas Gohr    }
199b6632b6eSAndreas Gohr
200b6632b6eSAndreas Gohr
201b6632b6eSAndreas Gohr    /**
202b6632b6eSAndreas Gohr     * Return some trend data about visits and edits in the wiki
203f9e60319SAndreas Gohr     *
204f9e60319SAndreas Gohr     * @param bool $hours Use hour resolution rather than days
205f9e60319SAndreas Gohr     * @return array
206b6632b6eSAndreas Gohr     */
207f9e60319SAndreas Gohr    public function dashboardviews(bool $hours = false): array
208b6632b6eSAndreas Gohr    {
209b6632b6eSAndreas Gohr        if ($hours) {
21010dcb86fSAndreas Gohr            $TIME = 'strftime(\'%H\', P.dt)';
211b6632b6eSAndreas Gohr        } else {
21210dcb86fSAndreas Gohr            $TIME = 'DATE(P.dt)';
213b6632b6eSAndreas Gohr        }
214b6632b6eSAndreas Gohr
215b6632b6eSAndreas Gohr        $data = [];
216b6632b6eSAndreas Gohr
217b6632b6eSAndreas Gohr        // access trends
218b6632b6eSAndreas Gohr        $sql = "SELECT $TIME as time,
21910dcb86fSAndreas Gohr                       COUNT(DISTINCT P.session) as sessions,
22010dcb86fSAndreas Gohr                       COUNT(P.session) as pageviews,
22110dcb86fSAndreas Gohr                       COUNT(DISTINCT S.uid) as visitors
22210dcb86fSAndreas Gohr                  FROM pageviews as P
22310dcb86fSAndreas Gohr                  LEFT JOIN sessions as S ON P.session = S.session
22410dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
225*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
226b6632b6eSAndreas Gohr              GROUP BY $TIME
227b6632b6eSAndreas Gohr              ORDER BY time";
228*30cf9434SAndreas Gohr        $result = $this->db->queryAll($sql, [$this->from, $this->to]);
229b6632b6eSAndreas Gohr        foreach ($result as $row) {
230b6632b6eSAndreas Gohr            $data[$row['time']]['sessions'] = $row['sessions'];
231b6632b6eSAndreas Gohr            $data[$row['time']]['pageviews'] = $row['pageviews'];
232b6632b6eSAndreas Gohr            $data[$row['time']]['visitors'] = $row['visitors'];
233b6632b6eSAndreas Gohr        }
234b6632b6eSAndreas Gohr        return $data;
235b6632b6eSAndreas Gohr    }
236b6632b6eSAndreas Gohr
237f9e60319SAndreas Gohr    /**
238f9e60319SAndreas Gohr     * @param bool $hours Use hour resolution rather than days
239f9e60319SAndreas Gohr     * @return array
240f9e60319SAndreas Gohr     */
241f9e60319SAndreas Gohr    public function dashboardwiki(bool $hours = false): array
242b6632b6eSAndreas Gohr    {
243b6632b6eSAndreas Gohr        if ($hours) {
2447428e816SAndreas Gohr            $TIME = 'strftime(\'%H\', dt)';
245b6632b6eSAndreas Gohr        } else {
246b6632b6eSAndreas Gohr            $TIME = 'DATE(dt)';
247b6632b6eSAndreas Gohr        }
248b6632b6eSAndreas Gohr
249b6632b6eSAndreas Gohr        $data = [];
250b6632b6eSAndreas Gohr
251b6632b6eSAndreas Gohr        // edit trends
252b6632b6eSAndreas Gohr        foreach (['E', 'C', 'D'] as $type) {
253b6632b6eSAndreas Gohr            $sql = "SELECT $TIME as time,
254b6632b6eSAndreas Gohr                           COUNT(*) as cnt
2557428e816SAndreas Gohr                      FROM edits as A
2567428e816SAndreas Gohr                     WHERE A.dt >= ? AND A.dt <= ?
257*30cf9434SAndreas Gohr                       AND type = '$type'
258b6632b6eSAndreas Gohr                  GROUP BY $TIME
259b6632b6eSAndreas Gohr                  ORDER BY time";
260*30cf9434SAndreas Gohr            $result = $this->db->queryAll($sql, [$this->from, $this->to]);
261b6632b6eSAndreas Gohr            foreach ($result as $row) {
262b6632b6eSAndreas Gohr                $data[$row['time']][$type] = $row['cnt'];
263b6632b6eSAndreas Gohr            }
264b6632b6eSAndreas Gohr        }
265b6632b6eSAndreas Gohr        ksort($data);
266b6632b6eSAndreas Gohr        return $data;
267b6632b6eSAndreas Gohr    }
268b6632b6eSAndreas Gohr
269f9e60319SAndreas Gohr    /**
270f9e60319SAndreas Gohr     * @param string $info Which type of history to select (FIXME which ones are there?)
271f9e60319SAndreas Gohr     * @param string $interval Group data by this interval (days, weeks, months)
272f9e60319SAndreas Gohr     * @return array
273f9e60319SAndreas Gohr     */
274f9e60319SAndreas Gohr    public function history(string $info, string $interval = 'day'): array
275b6632b6eSAndreas Gohr    {
276b6632b6eSAndreas Gohr        if ($interval == 'weeks') {
2777428e816SAndreas Gohr            $TIME = 'strftime(\'%Y\', dt), strftime(\'%W\', dt)';
278b6632b6eSAndreas Gohr        } elseif ($interval == 'months') {
2797428e816SAndreas Gohr            $TIME = 'strftime(\'%Y-%m\', dt)';
280b6632b6eSAndreas Gohr        } else {
281a087824eSAnna Dabrowska            $TIME = 'strftime(\'%d-%m\', dt)';
282b6632b6eSAndreas Gohr        }
283b6632b6eSAndreas Gohr
284b6632b6eSAndreas Gohr        $mod = 1;
285b6632b6eSAndreas Gohr        if ($info == 'media_size' || $info == 'page_size') {
286b6632b6eSAndreas Gohr            $mod = 1024 * 1024;
287b6632b6eSAndreas Gohr        }
288b6632b6eSAndreas Gohr
289b6632b6eSAndreas Gohr        $sql = "SELECT $TIME as time,
2907428e816SAndreas Gohr                       AVG(value)/$mod as cnt
2917428e816SAndreas Gohr                  FROM history as A
2927428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
2937428e816SAndreas Gohr                   AND info = ?
294b6632b6eSAndreas Gohr                  GROUP BY $TIME
295b6632b6eSAndreas Gohr                  ORDER BY $TIME";
296f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, $info]);
297b6632b6eSAndreas Gohr    }
298b6632b6eSAndreas Gohr
299f9e60319SAndreas Gohr    /**
300f9e60319SAndreas Gohr     * @return array
301f9e60319SAndreas Gohr     */
302f9e60319SAndreas Gohr    public function searchengines(): array
303b6632b6eSAndreas Gohr    {
30410dcb86fSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, R.engine
3056f2bdce1SAndreas Gohr                  FROM pageviews as P,
3066f2bdce1SAndreas Gohr                       referers as R
30710dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
3086f2bdce1SAndreas Gohr                   AND P.ref_id = R.id
30910dcb86fSAndreas Gohr                   AND R.engine != ''
31010dcb86fSAndreas Gohr              GROUP BY R.engine
31110dcb86fSAndreas Gohr              ORDER BY cnt DESC, R.engine" .
312f9e60319SAndreas Gohr            $this->limit;
313f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
314b6632b6eSAndreas Gohr    }
315b6632b6eSAndreas Gohr
316f9e60319SAndreas Gohr    /**
317f9e60319SAndreas Gohr     * @return array
318f9e60319SAndreas Gohr     */
3192a30f557SAndreas Gohr    public function searchphrases(): array
320b6632b6eSAndreas Gohr    {
3212a30f557SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, query, query as ilookup
3222a30f557SAndreas Gohr                  FROM search
3232a30f557SAndreas Gohr                 WHERE dt >= ? AND dt <= ?
3242a30f557SAndreas Gohr              GROUP BY query
3252a30f557SAndreas Gohr              ORDER BY cnt DESC, query" .
326f9e60319SAndreas Gohr            $this->limit;
3272a30f557SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
328b6632b6eSAndreas Gohr    }
329b6632b6eSAndreas Gohr
330f9e60319SAndreas Gohr    /**
331f9e60319SAndreas Gohr     * @return array
332f9e60319SAndreas Gohr     */
3332a30f557SAndreas Gohr    public function searchwords(): array
334b6632b6eSAndreas Gohr    {
3352a30f557SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, SW.word, SW.word as ilookup
3362a30f557SAndreas Gohr                  FROM search as S,
3372a30f557SAndreas Gohr                       searchwords as SW
33810dcb86fSAndreas Gohr                 WHERE S.dt >= ? AND S.dt <= ?
3392a30f557SAndreas Gohr                   AND S.id = SW.sid
34010dcb86fSAndreas Gohr              GROUP BY SW.word
34110dcb86fSAndreas Gohr              ORDER BY cnt DESC, SW.word" .
342f9e60319SAndreas Gohr            $this->limit;
3432a30f557SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
344b6632b6eSAndreas Gohr    }
345b6632b6eSAndreas Gohr
346f9e60319SAndreas Gohr    /**
347f9e60319SAndreas Gohr     * @return array
348f9e60319SAndreas Gohr     */
349f9e60319SAndreas Gohr    public function outlinks(): array
350b6632b6eSAndreas Gohr    {
351b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, link as url
3527428e816SAndreas Gohr                  FROM outlinks as A
3537428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
354b6632b6eSAndreas Gohr              GROUP BY link
355b6632b6eSAndreas Gohr              ORDER BY cnt DESC, link" .
356f9e60319SAndreas Gohr            $this->limit;
357f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
358b6632b6eSAndreas Gohr    }
359b6632b6eSAndreas Gohr
360f9e60319SAndreas Gohr    /**
361f9e60319SAndreas Gohr     * @return array
362f9e60319SAndreas Gohr     */
363f9e60319SAndreas Gohr    public function pages(): array
364b6632b6eSAndreas Gohr    {
36510dcb86fSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, P.page
3666f2bdce1SAndreas Gohr                  FROM pageviews as P,
3676f2bdce1SAndreas Gohr                       sessions as S
36810dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
3696f2bdce1SAndreas Gohr                   AND P.session = S.session
370*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
37110dcb86fSAndreas Gohr              GROUP BY P.page
37210dcb86fSAndreas Gohr              ORDER BY cnt DESC, P.page" .
373f9e60319SAndreas Gohr            $this->limit;
374*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
375b6632b6eSAndreas Gohr    }
376b6632b6eSAndreas Gohr
377f9e60319SAndreas Gohr    /**
378f9e60319SAndreas Gohr     * @return array
379f9e60319SAndreas Gohr     */
380f9e60319SAndreas Gohr    public function edits(): array
381b6632b6eSAndreas Gohr    {
382b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, page
3837428e816SAndreas Gohr                  FROM edits as A
3847428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
385b6632b6eSAndreas Gohr              GROUP BY page
386b6632b6eSAndreas Gohr              ORDER BY cnt DESC, page" .
387f9e60319SAndreas Gohr            $this->limit;
388f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
389b6632b6eSAndreas Gohr    }
390b6632b6eSAndreas Gohr
391f9e60319SAndreas Gohr    /**
392f9e60319SAndreas Gohr     * @return array
393f9e60319SAndreas Gohr     */
394f9e60319SAndreas Gohr    public function images(): array
395b6632b6eSAndreas Gohr    {
396b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, media, SUM(size) as filesize
3977428e816SAndreas Gohr                  FROM media as A
3987428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
399*30cf9434SAndreas Gohr                   AND mime1 = 'image'
400b6632b6eSAndreas Gohr              GROUP BY media
401b6632b6eSAndreas Gohr              ORDER BY cnt DESC, media" .
402f9e60319SAndreas Gohr            $this->limit;
403*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
404b6632b6eSAndreas Gohr    }
405b6632b6eSAndreas Gohr
406f9e60319SAndreas Gohr    /**
407f9e60319SAndreas Gohr     * @return array
408f9e60319SAndreas Gohr     */
409f9e60319SAndreas Gohr    public function imagessum(): array
410b6632b6eSAndreas Gohr    {
411b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, SUM(size) as filesize
4127428e816SAndreas Gohr                  FROM media as A
4137428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
414*30cf9434SAndreas Gohr                   AND mime1 = 'image'";
415*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
416b6632b6eSAndreas Gohr    }
417b6632b6eSAndreas Gohr
418f9e60319SAndreas Gohr    /**
419f9e60319SAndreas Gohr     * @return array
420f9e60319SAndreas Gohr     */
421f9e60319SAndreas Gohr    public function downloads(): array
422b6632b6eSAndreas Gohr    {
423b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, media, SUM(size) as filesize
4247428e816SAndreas Gohr                  FROM media as A
4257428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
426*30cf9434SAndreas Gohr                   AND mime1 != 'image'
427b6632b6eSAndreas Gohr              GROUP BY media
428b6632b6eSAndreas Gohr              ORDER BY cnt DESC, media" .
429f9e60319SAndreas Gohr            $this->limit;
430*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
431b6632b6eSAndreas Gohr    }
432b6632b6eSAndreas Gohr
433f9e60319SAndreas Gohr    /**
434f9e60319SAndreas Gohr     * @return array
435f9e60319SAndreas Gohr     */
436f9e60319SAndreas Gohr    public function downloadssum(): array
437b6632b6eSAndreas Gohr    {
438b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, SUM(size) as filesize
4397428e816SAndreas Gohr                  FROM media as A
4407428e816SAndreas Gohr                 WHERE A.dt >= ? AND A.dt <= ?
441*30cf9434SAndreas Gohr                   AND mime1 != 'image'";
442*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
443b6632b6eSAndreas Gohr    }
444b6632b6eSAndreas Gohr
445f9e60319SAndreas Gohr    /**
446f9e60319SAndreas Gohr     * @return array
447f9e60319SAndreas Gohr     */
448f9e60319SAndreas Gohr    public function referer(): array
449b6632b6eSAndreas Gohr    {
45010dcb86fSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, R.url
45110dcb86fSAndreas Gohr                  FROM pageviews as P
45210dcb86fSAndreas Gohr                  LEFT JOIN sessions as S ON P.session = S.session
45310dcb86fSAndreas Gohr                  LEFT JOIN referers as R ON P.ref_id = R.id
45410dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
455*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
45610dcb86fSAndreas Gohr                   AND R.url IS NOT NULL
45710dcb86fSAndreas Gohr                   AND R.url != ''
45810dcb86fSAndreas Gohr                   AND R.engine IS NULL
45910dcb86fSAndreas Gohr              GROUP BY R.url
46010dcb86fSAndreas Gohr              ORDER BY cnt DESC, R.url" .
461f9e60319SAndreas Gohr            $this->limit;
462*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
463b6632b6eSAndreas Gohr    }
464b6632b6eSAndreas Gohr
465f9e60319SAndreas Gohr    /**
466f9e60319SAndreas Gohr     * @return array
467f9e60319SAndreas Gohr     */
468f9e60319SAndreas Gohr    public function newreferer(): array
469b6632b6eSAndreas Gohr    {
47010dcb86fSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, R.url
47110dcb86fSAndreas Gohr                  FROM pageviews as P
47210dcb86fSAndreas Gohr                  LEFT JOIN sessions as S ON P.session = S.session
47310dcb86fSAndreas Gohr                  LEFT JOIN referers as R ON P.ref_id = R.id
47410dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
475*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
47610dcb86fSAndreas Gohr                   AND R.url IS NOT NULL
47710dcb86fSAndreas Gohr                   AND R.url != ''
47810dcb86fSAndreas Gohr                   AND R.engine IS NULL
47910dcb86fSAndreas Gohr                   AND R.dt >= ?
48010dcb86fSAndreas Gohr              GROUP BY R.url
48110dcb86fSAndreas Gohr              ORDER BY cnt DESC, R.url" .
482f9e60319SAndreas Gohr            $this->limit;
483*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to, $this->from]);
484b6632b6eSAndreas Gohr    }
485b6632b6eSAndreas Gohr
486f9e60319SAndreas Gohr    /**
487f9e60319SAndreas Gohr     * @return array
488f9e60319SAndreas Gohr     */
489f9e60319SAndreas Gohr    public function countries(): array
490b6632b6eSAndreas Gohr    {
49110dcb86fSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT P.session) as cnt, I.country
4926f2bdce1SAndreas Gohr                  FROM pageviews as P,
4936f2bdce1SAndreas Gohr                       iplocation as I
49410dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
4956f2bdce1SAndreas Gohr                   AND P.ip = I.ip
49610dcb86fSAndreas Gohr                   AND I.country != ''
49710dcb86fSAndreas Gohr              GROUP BY I.code
49810dcb86fSAndreas Gohr              ORDER BY cnt DESC, I.country" .
499f9e60319SAndreas Gohr            $this->limit;
500f9e60319SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
501b6632b6eSAndreas Gohr    }
502b6632b6eSAndreas Gohr
503f9e60319SAndreas Gohr    /**
504f9e60319SAndreas Gohr     * @param bool $ext return extended information
505f9e60319SAndreas Gohr     * @return array
506f9e60319SAndreas Gohr     */
5072a30f557SAndreas Gohr    public function browsers(bool $ext = false): array
508b6632b6eSAndreas Gohr    {
509b6632b6eSAndreas Gohr        if ($ext) {
51010dcb86fSAndreas Gohr            $sel = 'S.ua_info as browser, S.ua_ver';
51110dcb86fSAndreas Gohr            $grp = 'S.ua_info, S.ua_ver';
512b6632b6eSAndreas Gohr        } else {
5132a30f557SAndreas Gohr            $sel = 'S.ua_info as browser';
51410dcb86fSAndreas Gohr            $grp = 'S.ua_info';
515b6632b6eSAndreas Gohr        }
516b6632b6eSAndreas Gohr
51710dcb86fSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT S.session) as cnt, $sel
51810dcb86fSAndreas Gohr                  FROM sessions as S
51910dcb86fSAndreas Gohr                 WHERE S.dt >= ? AND S.dt <= ?
520*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
521b6632b6eSAndreas Gohr              GROUP BY $grp
52210dcb86fSAndreas Gohr              ORDER BY cnt DESC, S.ua_info" .
523f9e60319SAndreas Gohr            $this->limit;
524*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
525b6632b6eSAndreas Gohr    }
526b6632b6eSAndreas Gohr
527f9e60319SAndreas Gohr    /**
528f9e60319SAndreas Gohr     * @return array
529f9e60319SAndreas Gohr     */
530f9e60319SAndreas Gohr    public function os(): array
531b6632b6eSAndreas Gohr    {
53210dcb86fSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT S.session) as cnt, S.os
53310dcb86fSAndreas Gohr                  FROM sessions as S
53410dcb86fSAndreas Gohr                 WHERE S.dt >= ? AND S.dt <= ?
535*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
53610dcb86fSAndreas Gohr              GROUP BY S.os
53710dcb86fSAndreas Gohr              ORDER BY cnt DESC, S.os" .
538f9e60319SAndreas Gohr            $this->limit;
539*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
540b6632b6eSAndreas Gohr    }
541b6632b6eSAndreas Gohr
542f9e60319SAndreas Gohr    /**
543f9e60319SAndreas Gohr     * @return array
544f9e60319SAndreas Gohr     */
5459fdd7e51SAndreas Gohr    public function topdomain(): array
5469fdd7e51SAndreas Gohr    {
5479fdd7e51SAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, U.domain
5489fdd7e51SAndreas Gohr                  FROM pageviews as P,
5499fdd7e51SAndreas Gohr                       sessions as S,
5509fdd7e51SAndreas Gohr                       users as U
5519fdd7e51SAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
5529fdd7e51SAndreas Gohr                   AND P.session = S.session
5539fdd7e51SAndreas Gohr                   AND S.user = U.user
554*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
5559fdd7e51SAndreas Gohr                   AND S.user IS NOT NULL
556*30cf9434SAndreas Gohr                   AND S.user != ''
5579fdd7e51SAndreas Gohr              GROUP BY U.domain
5589fdd7e51SAndreas Gohr              ORDER BY cnt DESC, U.domain" .
5599fdd7e51SAndreas Gohr            $this->limit;
560*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
5619fdd7e51SAndreas Gohr    }
5629fdd7e51SAndreas Gohr
5639fdd7e51SAndreas Gohr    /**
5649fdd7e51SAndreas Gohr     * @return array
5659fdd7e51SAndreas Gohr     */
566f9e60319SAndreas Gohr    public function topuser(): array
567b6632b6eSAndreas Gohr    {
56810dcb86fSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, S.user
5696f2bdce1SAndreas Gohr                  FROM pageviews as P,
5706f2bdce1SAndreas Gohr                       sessions as S
57110dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
5726f2bdce1SAndreas Gohr                   AND P.session = S.session
573*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
574*30cf9434SAndreas Gohr                   AND S.user != ''
57510dcb86fSAndreas Gohr              GROUP BY S.user
57610dcb86fSAndreas Gohr              ORDER BY cnt DESC, S.user" .
577f9e60319SAndreas Gohr            $this->limit;
578*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
579b6632b6eSAndreas Gohr    }
580b6632b6eSAndreas Gohr
581f9e60319SAndreas Gohr    /**
582f9e60319SAndreas Gohr     * @return array
583f9e60319SAndreas Gohr     */
584f9e60319SAndreas Gohr    public function topeditor(): array
585b6632b6eSAndreas Gohr    {
586b6632b6eSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, user
5876f2bdce1SAndreas Gohr                  FROM edits as E,
5886f2bdce1SAndreas Gohr                       sessions as S
58910dcb86fSAndreas Gohr                 WHERE E.dt >= ? AND E.dt <= ?
5906f2bdce1SAndreas Gohr                   AND E.session = S.session
591*30cf9434SAndreas Gohr                   AND S.user != ''
592b6632b6eSAndreas Gohr              GROUP BY user
593b6632b6eSAndreas Gohr              ORDER BY cnt DESC, user" .
594f9e60319SAndreas Gohr            $this->limit;
595*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
596b6632b6eSAndreas Gohr    }
597b6632b6eSAndreas Gohr
598f9e60319SAndreas Gohr    /**
599f9e60319SAndreas Gohr     * @return array
600f9e60319SAndreas Gohr     */
601f9e60319SAndreas Gohr    public function topgroup(): array
602b6632b6eSAndreas Gohr    {
60310dcb86fSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, G.`group`
6046f2bdce1SAndreas Gohr                  FROM pageviews as P,
6056f2bdce1SAndreas Gohr                       sessions as S,
6066f2bdce1SAndreas Gohr                       groups as G
60710dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
6086f2bdce1SAndreas Gohr                   AND P.session = S.session
6096f2bdce1SAndreas Gohr                   AND S.user = G.user
610*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
61110dcb86fSAndreas Gohr              GROUP BY G.`group`
61210dcb86fSAndreas Gohr              ORDER BY cnt DESC, G.`group`" .
613f9e60319SAndreas Gohr            $this->limit;
614*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
615b6632b6eSAndreas Gohr    }
616b6632b6eSAndreas Gohr
617f9e60319SAndreas Gohr    /**
618f9e60319SAndreas Gohr     * @return array
619f9e60319SAndreas Gohr     */
620f9e60319SAndreas Gohr    public function topgroupedit(): array
621b6632b6eSAndreas Gohr    {
62210dcb86fSAndreas Gohr        $sql = "SELECT COUNT(*) as cnt, G.`group`
6236f2bdce1SAndreas Gohr                  FROM edits as E,
6246f2bdce1SAndreas Gohr                       sessions as S,
6256f2bdce1SAndreas Gohr                       groups as G
62610dcb86fSAndreas Gohr                 WHERE E.dt >= ? AND E.dt <= ?
6276f2bdce1SAndreas Gohr                   AND E.session = S.session
6286f2bdce1SAndreas Gohr                   AND S.user = G.user
62910dcb86fSAndreas Gohr              GROUP BY G.`group`
63010dcb86fSAndreas Gohr              ORDER BY cnt DESC, G.`group`" .
631f9e60319SAndreas Gohr            $this->limit;
63210dcb86fSAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
633b6632b6eSAndreas Gohr    }
634b6632b6eSAndreas Gohr
635b6632b6eSAndreas Gohr
636f9e60319SAndreas Gohr    /**
637f9e60319SAndreas Gohr     * @return array
638f9e60319SAndreas Gohr     */
639f9e60319SAndreas Gohr    public function resolution(): array
640b6632b6eSAndreas Gohr    {
64110dcb86fSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT S.uid) as cnt,
64210dcb86fSAndreas Gohr                       ROUND(P.screen_x/100)*100 as res_x,
64310dcb86fSAndreas Gohr                       ROUND(P.screen_y/100)*100 as res_y,
64410dcb86fSAndreas Gohr                       CAST(ROUND(P.screen_x/100)*100 AS int) || 'x' || CAST(ROUND(P.screen_y/100)*100 AS int) as resolution
6456f2bdce1SAndreas Gohr                  FROM pageviews as P,
6466f2bdce1SAndreas Gohr                       sessions as S
64710dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
6486f2bdce1SAndreas Gohr                   AND P.session = S.session
649*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
650*30cf9434SAndreas Gohr                   AND P.screen_x != 0
651*30cf9434SAndreas Gohr                   AND P.screen_y != 0
652b6632b6eSAndreas Gohr              GROUP BY resolution
653b6632b6eSAndreas Gohr              ORDER BY cnt DESC" .
654f9e60319SAndreas Gohr            $this->limit;
655*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
656b6632b6eSAndreas Gohr    }
657b6632b6eSAndreas Gohr
658f9e60319SAndreas Gohr    /**
659f9e60319SAndreas Gohr     * @return array
660f9e60319SAndreas Gohr     */
661f9e60319SAndreas Gohr    public function viewport(): array
662b6632b6eSAndreas Gohr    {
66310dcb86fSAndreas Gohr        $sql = "SELECT COUNT(DISTINCT S.uid) as cnt,
66410dcb86fSAndreas Gohr                       ROUND(P.view_x/100)*100 as res_x,
66510dcb86fSAndreas Gohr                       ROUND(P.view_y/100)*100 as res_y,
66610dcb86fSAndreas Gohr                       CAST(ROUND(P.view_x/100)*100 AS int) || 'x' || CAST(ROUND(P.view_y/100)*100 AS int) as resolution
6676f2bdce1SAndreas Gohr                  FROM pageviews as P,
6686f2bdce1SAndreas Gohr                       sessions as S
66910dcb86fSAndreas Gohr                 WHERE P.dt >= ? AND P.dt <= ?
6706f2bdce1SAndreas Gohr                   AND P.session = S.session
671*30cf9434SAndreas Gohr                   AND S.ua_type = 'browser'
672*30cf9434SAndreas Gohr                   AND P.view_x != 0
673*30cf9434SAndreas Gohr                   AND P.view_y != 0
674b6632b6eSAndreas Gohr              GROUP BY resolution
675b6632b6eSAndreas Gohr              ORDER BY cnt DESC" .
676f9e60319SAndreas Gohr            $this->limit;
677b6632b6eSAndreas Gohr
678*30cf9434SAndreas Gohr        return $this->db->queryAll($sql, [$this->from, $this->to]);
679b6632b6eSAndreas Gohr    }
680b6632b6eSAndreas Gohr
681f9e60319SAndreas Gohr    /**
682f9e60319SAndreas Gohr     * @return array
683f9e60319SAndreas Gohr     */
684f9e60319SAndreas Gohr    public function seenusers(): array
685b6632b6eSAndreas Gohr    {
68610dcb86fSAndreas Gohr        $sql = "SELECT `user`, MAX(`dt`) as dt
68710dcb86fSAndreas Gohr                  FROM users
68810dcb86fSAndreas Gohr                 WHERE `user` IS NOT NULL
68910dcb86fSAndreas Gohr                   AND `user` != ''
69010dcb86fSAndreas Gohr              GROUP BY `user`
691b6632b6eSAndreas Gohr              ORDER BY `dt` DESC" .
692f9e60319SAndreas Gohr            $this->limit;
693b6632b6eSAndreas Gohr
694f9e60319SAndreas Gohr        return $this->db->queryAll($sql);
695b6632b6eSAndreas Gohr    }
696b6632b6eSAndreas Gohr}
697