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 79*10dcb86fSAndreas Gohr // Count referrer types by joining with referers table 80*10dcb86fSAndreas Gohr $sql = "SELECT 81*10dcb86fSAndreas Gohr CASE 82*10dcb86fSAndreas Gohr WHEN R.engine IS NOT NULL THEN 'search' 83*10dcb86fSAndreas Gohr WHEN R.url IS NOT NULL AND R.url != '' THEN 'external' 84*10dcb86fSAndreas Gohr ELSE 'direct' 85*10dcb86fSAndreas Gohr END as ref_type, 86*10dcb86fSAndreas Gohr COUNT(*) as cnt 87*10dcb86fSAndreas Gohr FROM pageviews as P 88*10dcb86fSAndreas Gohr LEFT JOIN referers as R ON P.ref_id = R.id 89*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 90*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 91*10dcb86fSAndreas Gohr AND S.ua_type = ? 92b6632b6eSAndreas Gohr GROUP BY ref_type"; 93f9e60319SAndreas Gohr $result = $this->db->queryAll($sql, [$this->from, $this->to, 'browser']); 94b6632b6eSAndreas Gohr 95f9e60319SAndreas Gohr foreach ($result as $row) { 96b6632b6eSAndreas Gohr if ($row['ref_type'] == 'search') $data['search'] = $row['cnt']; 97b6632b6eSAndreas Gohr if ($row['ref_type'] == 'external') $data['external'] = $row['cnt']; 98b6632b6eSAndreas Gohr if ($row['ref_type'] == 'internal') $data['internal'] = $row['cnt']; 99*10dcb86fSAndreas Gohr if ($row['ref_type'] == 'direct') $data['direct'] = $row['cnt']; 100b6632b6eSAndreas Gohr } 101b6632b6eSAndreas Gohr 102b6632b6eSAndreas Gohr // general user and session info 103*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT P.session) as sessions, 104*10dcb86fSAndreas Gohr COUNT(P.session) as views, 105*10dcb86fSAndreas Gohr COUNT(DISTINCT S.user) as users, 106*10dcb86fSAndreas Gohr COUNT(DISTINCT S.uid) as visitors 107*10dcb86fSAndreas Gohr FROM pageviews as P 108*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 109*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 110*10dcb86fSAndreas Gohr AND S.ua_type = ?"; 111f9e60319SAndreas Gohr $result = $this->db->queryRecord($sql, [$this->from, $this->to, 'browser']); 112b6632b6eSAndreas Gohr 113*10dcb86fSAndreas Gohr $data['users'] = $result['users']; 114f9e60319SAndreas Gohr $data['sessions'] = $result['sessions']; 115f9e60319SAndreas Gohr $data['pageviews'] = $result['views']; 116f9e60319SAndreas Gohr $data['visitors'] = $result['visitors']; 117b6632b6eSAndreas Gohr 118*10dcb86fSAndreas Gohr // calculate bounce rate (sessions with only 1 page view) 119b6632b6eSAndreas Gohr if ($data['sessions']) { 120b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt 121*10dcb86fSAndreas Gohr FROM ( 122*10dcb86fSAndreas Gohr SELECT P.session, COUNT(*) as views 123*10dcb86fSAndreas Gohr FROM pageviews as P 124*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 125*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 126*10dcb86fSAndreas Gohr AND S.ua_type = ? 127*10dcb86fSAndreas Gohr GROUP BY P.session 128*10dcb86fSAndreas Gohr HAVING views = 1 129*10dcb86fSAndreas Gohr )"; 130*10dcb86fSAndreas Gohr $count = $this->db->queryValue($sql, [$this->from, $this->to, 'browser']); 131f9e60319SAndreas Gohr $data['bouncerate'] = $count * 100 / $data['sessions']; 132f9e60319SAndreas Gohr $data['newvisitors'] = $count * 100 / $data['sessions']; 133b6632b6eSAndreas Gohr } 134b6632b6eSAndreas Gohr 135b6632b6eSAndreas Gohr // calculate avg. number of views per session 136b6632b6eSAndreas Gohr $sql = "SELECT AVG(views) as cnt 137*10dcb86fSAndreas Gohr FROM ( 138*10dcb86fSAndreas Gohr SELECT P.session, COUNT(*) as views 139*10dcb86fSAndreas Gohr FROM pageviews as P 140*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 141*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 142*10dcb86fSAndreas Gohr AND S.ua_type = ? 143*10dcb86fSAndreas Gohr GROUP BY P.session 144*10dcb86fSAndreas Gohr )"; 145*10dcb86fSAndreas Gohr $data['avgpages'] = $this->db->queryValue($sql, [$this->from, $this->to, 'browser']); 146b6632b6eSAndreas Gohr 147b6632b6eSAndreas Gohr // average time spent on the site 148*10dcb86fSAndreas Gohr $sql = "SELECT AVG((julianday(end) - julianday(dt)) * 24 * 60) as time 149*10dcb86fSAndreas Gohr FROM sessions as S 150*10dcb86fSAndreas Gohr WHERE S.dt >= ? AND S.dt <= ? 151*10dcb86fSAndreas Gohr AND S.dt != S.end 152*10dcb86fSAndreas Gohr AND DATE(S.dt) = DATE(S.end) 153*10dcb86fSAndreas Gohr AND S.ua_type = ?"; 154*10dcb86fSAndreas Gohr $data['timespent'] = $this->db->queryValue($sql, [$this->from, $this->to, 'browser']); 155b6632b6eSAndreas Gohr 156b6632b6eSAndreas Gohr // logins 157b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as logins 1587428e816SAndreas Gohr FROM logins as A 1597428e816SAndreas Gohr WHERE A.dt >= ? AND A.dt <= ? 1607428e816SAndreas Gohr AND (type = ? OR type = ?)"; 161f9e60319SAndreas Gohr $data['logins'] = $this->db->queryValue($sql, [$this->from, $this->to, 'l', 'p']); 162b6632b6eSAndreas Gohr 163b6632b6eSAndreas Gohr // registrations 164b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as registrations 1657428e816SAndreas Gohr FROM logins as A 1667428e816SAndreas Gohr WHERE A.dt >= ? AND A.dt <= ? 1677428e816SAndreas Gohr AND type = ?"; 168f9e60319SAndreas Gohr $data['registrations'] = $this->db->queryValue($sql, [$this->from, $this->to, 'C']); 169b6632b6eSAndreas Gohr 170*10dcb86fSAndreas Gohr // current users (based on recent sessions) 171*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT uid) as current 172*10dcb86fSAndreas Gohr FROM sessions 173*10dcb86fSAndreas Gohr WHERE end >= datetime('now', '-10 minutes')"; 174f9e60319SAndreas Gohr $data['current'] = $this->db->queryValue($sql); 175b6632b6eSAndreas Gohr 176b6632b6eSAndreas Gohr return $data; 177b6632b6eSAndreas Gohr } 178b6632b6eSAndreas Gohr 179b6632b6eSAndreas Gohr 180b6632b6eSAndreas Gohr /** 181b6632b6eSAndreas Gohr * Return some trend data about visits and edits in the wiki 182f9e60319SAndreas Gohr * 183f9e60319SAndreas Gohr * @param bool $hours Use hour resolution rather than days 184f9e60319SAndreas Gohr * @return array 185b6632b6eSAndreas Gohr */ 186f9e60319SAndreas Gohr public function dashboardviews(bool $hours = false): array 187b6632b6eSAndreas Gohr { 188b6632b6eSAndreas Gohr if ($hours) { 189*10dcb86fSAndreas Gohr $TIME = 'strftime(\'%H\', P.dt)'; 190b6632b6eSAndreas Gohr } else { 191*10dcb86fSAndreas Gohr $TIME = 'DATE(P.dt)'; 192b6632b6eSAndreas Gohr } 193b6632b6eSAndreas Gohr 194b6632b6eSAndreas Gohr $data = []; 195b6632b6eSAndreas Gohr 196b6632b6eSAndreas Gohr // access trends 197b6632b6eSAndreas Gohr $sql = "SELECT $TIME as time, 198*10dcb86fSAndreas Gohr COUNT(DISTINCT P.session) as sessions, 199*10dcb86fSAndreas Gohr COUNT(P.session) as pageviews, 200*10dcb86fSAndreas Gohr COUNT(DISTINCT S.uid) as visitors 201*10dcb86fSAndreas Gohr FROM pageviews as P 202*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 203*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 204*10dcb86fSAndreas Gohr AND S.ua_type = ? 205b6632b6eSAndreas Gohr GROUP BY $TIME 206b6632b6eSAndreas Gohr ORDER BY time"; 207f9e60319SAndreas Gohr $result = $this->db->queryAll($sql, [$this->from, $this->to, 'browser']); 208b6632b6eSAndreas Gohr foreach ($result as $row) { 209b6632b6eSAndreas Gohr $data[$row['time']]['sessions'] = $row['sessions']; 210b6632b6eSAndreas Gohr $data[$row['time']]['pageviews'] = $row['pageviews']; 211b6632b6eSAndreas Gohr $data[$row['time']]['visitors'] = $row['visitors']; 212b6632b6eSAndreas Gohr } 213b6632b6eSAndreas Gohr return $data; 214b6632b6eSAndreas Gohr } 215b6632b6eSAndreas Gohr 216f9e60319SAndreas Gohr /** 217f9e60319SAndreas Gohr * @param bool $hours Use hour resolution rather than days 218f9e60319SAndreas Gohr * @return array 219f9e60319SAndreas Gohr */ 220f9e60319SAndreas Gohr public function dashboardwiki(bool $hours = false): array 221b6632b6eSAndreas Gohr { 222b6632b6eSAndreas Gohr if ($hours) { 2237428e816SAndreas Gohr $TIME = 'strftime(\'%H\', dt)'; 224b6632b6eSAndreas Gohr } else { 225b6632b6eSAndreas Gohr $TIME = 'DATE(dt)'; 226b6632b6eSAndreas Gohr } 227b6632b6eSAndreas Gohr 228b6632b6eSAndreas Gohr $data = []; 229b6632b6eSAndreas Gohr 230b6632b6eSAndreas Gohr // edit trends 231b6632b6eSAndreas Gohr foreach (['E', 'C', 'D'] as $type) { 232b6632b6eSAndreas Gohr $sql = "SELECT $TIME as time, 233b6632b6eSAndreas Gohr COUNT(*) as cnt 2347428e816SAndreas Gohr FROM edits as A 2357428e816SAndreas Gohr WHERE A.dt >= ? AND A.dt <= ? 2367428e816SAndreas Gohr AND type = ? 237b6632b6eSAndreas Gohr GROUP BY $TIME 238b6632b6eSAndreas Gohr ORDER BY time"; 239f9e60319SAndreas Gohr $result = $this->db->queryAll($sql, [$this->from, $this->to, $type]); 240b6632b6eSAndreas Gohr foreach ($result as $row) { 241b6632b6eSAndreas Gohr $data[$row['time']][$type] = $row['cnt']; 242b6632b6eSAndreas Gohr } 243b6632b6eSAndreas Gohr } 244b6632b6eSAndreas Gohr ksort($data); 245b6632b6eSAndreas Gohr return $data; 246b6632b6eSAndreas Gohr } 247b6632b6eSAndreas Gohr 248f9e60319SAndreas Gohr /** 249f9e60319SAndreas Gohr * @param string $info Which type of history to select (FIXME which ones are there?) 250f9e60319SAndreas Gohr * @param string $interval Group data by this interval (days, weeks, months) 251f9e60319SAndreas Gohr * @return array 252f9e60319SAndreas Gohr */ 253f9e60319SAndreas Gohr public function history(string $info, string $interval = 'day'): array 254b6632b6eSAndreas Gohr { 255b6632b6eSAndreas Gohr if ($interval == 'weeks') { 2567428e816SAndreas Gohr $TIME = 'strftime(\'%Y\', dt), strftime(\'%W\', dt)'; 257b6632b6eSAndreas Gohr } elseif ($interval == 'months') { 2587428e816SAndreas Gohr $TIME = 'strftime(\'%Y-%m\', dt)'; 259b6632b6eSAndreas Gohr } else { 260a087824eSAnna Dabrowska $TIME = 'strftime(\'%d-%m\', dt)'; 261b6632b6eSAndreas Gohr } 262b6632b6eSAndreas Gohr 263b6632b6eSAndreas Gohr $mod = 1; 264b6632b6eSAndreas Gohr if ($info == 'media_size' || $info == 'page_size') { 265b6632b6eSAndreas Gohr $mod = 1024 * 1024; 266b6632b6eSAndreas Gohr } 267b6632b6eSAndreas Gohr 268b6632b6eSAndreas Gohr $sql = "SELECT $TIME as time, 2697428e816SAndreas Gohr AVG(value)/$mod as cnt 2707428e816SAndreas Gohr FROM history as A 2717428e816SAndreas Gohr WHERE A.dt >= ? AND A.dt <= ? 2727428e816SAndreas Gohr AND info = ? 273b6632b6eSAndreas Gohr GROUP BY $TIME 274b6632b6eSAndreas Gohr ORDER BY $TIME"; 275f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, $info]); 276b6632b6eSAndreas Gohr } 277b6632b6eSAndreas Gohr 278f9e60319SAndreas Gohr /** 279f9e60319SAndreas Gohr * @return array 280f9e60319SAndreas Gohr */ 281f9e60319SAndreas Gohr public function searchengines(): array 282b6632b6eSAndreas Gohr { 283*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, R.engine 284*10dcb86fSAndreas Gohr FROM pageviews as P 285*10dcb86fSAndreas Gohr LEFT JOIN referers as R ON P.ref_id = R.id 286*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 287*10dcb86fSAndreas Gohr AND R.engine IS NOT NULL 288*10dcb86fSAndreas Gohr AND R.engine != '' 289*10dcb86fSAndreas Gohr GROUP BY R.engine 290*10dcb86fSAndreas Gohr ORDER BY cnt DESC, R.engine" . 291f9e60319SAndreas Gohr $this->limit; 292f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to]); 293b6632b6eSAndreas Gohr } 294b6632b6eSAndreas Gohr 295f9e60319SAndreas Gohr /** 296f9e60319SAndreas Gohr * @param bool $extern Limit results to external search engine (true) or dokuwiki (false) 297f9e60319SAndreas Gohr * @return array 298f9e60319SAndreas Gohr */ 299211caa5dSAndreas Gohr public function searchphrases(bool $extern = false): array 300b6632b6eSAndreas Gohr { 301b6632b6eSAndreas Gohr if ($extern) { 302*10dcb86fSAndreas Gohr $WHERE = "S.query != '' AND (R.engine IS NULL OR R.engine != ?)"; 3037428e816SAndreas Gohr $engineParam = 'dokuwiki'; 304b6632b6eSAndreas Gohr $I = ''; 305b6632b6eSAndreas Gohr } else { 306*10dcb86fSAndreas Gohr $WHERE = "S.query != '' AND R.engine = ?"; 3077428e816SAndreas Gohr $engineParam = 'dokuwiki'; 308b6632b6eSAndreas Gohr $I = 'i'; 309b6632b6eSAndreas Gohr } 310*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, S.query, S.query as ${I}lookup 311*10dcb86fSAndreas Gohr FROM search as S 312*10dcb86fSAndreas Gohr LEFT JOIN referers as R ON S.query = R.url 313*10dcb86fSAndreas Gohr WHERE S.dt >= ? AND S.dt <= ? 314b6632b6eSAndreas Gohr AND $WHERE 315*10dcb86fSAndreas Gohr GROUP BY S.query 316*10dcb86fSAndreas Gohr ORDER BY cnt DESC, S.query" . 317f9e60319SAndreas Gohr $this->limit; 318f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, $engineParam]); 319b6632b6eSAndreas Gohr } 320b6632b6eSAndreas Gohr 321f9e60319SAndreas Gohr /** 322f9e60319SAndreas Gohr * @param bool $extern Limit results to external search engine (true) or dokuwiki (false) 323f9e60319SAndreas Gohr * @return array 324f9e60319SAndreas Gohr */ 325211caa5dSAndreas Gohr public function searchwords(bool $extern = false): array 326b6632b6eSAndreas Gohr { 327b6632b6eSAndreas Gohr if ($extern) { 328*10dcb86fSAndreas Gohr $WHERE = "R.engine IS NULL OR R.engine != ?"; 3297428e816SAndreas Gohr $engineParam = 'dokuwiki'; 330b6632b6eSAndreas Gohr $I = ''; 331b6632b6eSAndreas Gohr } else { 332*10dcb86fSAndreas Gohr $WHERE = "R.engine = ?"; 3337428e816SAndreas Gohr $engineParam = 'dokuwiki'; 334b6632b6eSAndreas Gohr $I = 'i'; 335b6632b6eSAndreas Gohr } 336*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, SW.word, SW.word as ${I}lookup 337*10dcb86fSAndreas Gohr FROM search as S 338*10dcb86fSAndreas Gohr LEFT JOIN searchwords as SW ON S.id = SW.sid 339*10dcb86fSAndreas Gohr LEFT JOIN referers as R ON S.query = R.url 340*10dcb86fSAndreas Gohr WHERE S.dt >= ? AND S.dt <= ? 341*10dcb86fSAndreas Gohr AND SW.word IS NOT NULL 342b6632b6eSAndreas Gohr AND $WHERE 343*10dcb86fSAndreas Gohr GROUP BY SW.word 344*10dcb86fSAndreas Gohr ORDER BY cnt DESC, SW.word" . 345f9e60319SAndreas Gohr $this->limit; 346f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, $engineParam]); 347b6632b6eSAndreas Gohr } 348b6632b6eSAndreas Gohr 349f9e60319SAndreas Gohr /** 350f9e60319SAndreas Gohr * @return array 351f9e60319SAndreas Gohr */ 352f9e60319SAndreas Gohr public function outlinks(): array 353b6632b6eSAndreas Gohr { 354b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, link as url 3557428e816SAndreas Gohr FROM outlinks as A 3567428e816SAndreas Gohr WHERE A.dt >= ? AND A.dt <= ? 357b6632b6eSAndreas Gohr GROUP BY link 358b6632b6eSAndreas Gohr ORDER BY cnt DESC, link" . 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 pages(): array 367b6632b6eSAndreas Gohr { 368*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, P.page 369*10dcb86fSAndreas Gohr FROM pageviews as P 370*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 371*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 372*10dcb86fSAndreas Gohr AND S.ua_type = ? 373*10dcb86fSAndreas Gohr GROUP BY P.page 374*10dcb86fSAndreas Gohr ORDER BY cnt DESC, P.page" . 375f9e60319SAndreas Gohr $this->limit; 376f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'browser']); 377b6632b6eSAndreas Gohr } 378b6632b6eSAndreas Gohr 379f9e60319SAndreas Gohr /** 380f9e60319SAndreas Gohr * @return array 381f9e60319SAndreas Gohr */ 382f9e60319SAndreas Gohr public function edits(): array 383b6632b6eSAndreas Gohr { 384b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, page 3857428e816SAndreas Gohr FROM edits as A 3867428e816SAndreas Gohr WHERE A.dt >= ? AND A.dt <= ? 387b6632b6eSAndreas Gohr GROUP BY page 388b6632b6eSAndreas Gohr ORDER BY cnt DESC, page" . 389f9e60319SAndreas Gohr $this->limit; 390f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to]); 391b6632b6eSAndreas Gohr } 392b6632b6eSAndreas Gohr 393f9e60319SAndreas Gohr /** 394f9e60319SAndreas Gohr * @return array 395f9e60319SAndreas Gohr */ 396f9e60319SAndreas Gohr public function images(): array 397b6632b6eSAndreas Gohr { 398b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, media, SUM(size) as filesize 3997428e816SAndreas Gohr FROM media as A 4007428e816SAndreas Gohr WHERE A.dt >= ? AND A.dt <= ? 4017428e816SAndreas Gohr AND mime1 = ? 402b6632b6eSAndreas Gohr GROUP BY media 403b6632b6eSAndreas Gohr ORDER BY cnt DESC, media" . 404f9e60319SAndreas Gohr $this->limit; 405f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'image']); 406b6632b6eSAndreas Gohr } 407b6632b6eSAndreas Gohr 408f9e60319SAndreas Gohr /** 409f9e60319SAndreas Gohr * @return array 410f9e60319SAndreas Gohr */ 411f9e60319SAndreas Gohr public function imagessum(): array 412b6632b6eSAndreas Gohr { 413b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, SUM(size) as filesize 4147428e816SAndreas Gohr FROM media as A 4157428e816SAndreas Gohr WHERE A.dt >= ? AND A.dt <= ? 4167428e816SAndreas Gohr AND mime1 = ?"; 417f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'image']); 418b6632b6eSAndreas Gohr } 419b6632b6eSAndreas Gohr 420f9e60319SAndreas Gohr /** 421f9e60319SAndreas Gohr * @return array 422f9e60319SAndreas Gohr */ 423f9e60319SAndreas Gohr public function downloads(): array 424b6632b6eSAndreas Gohr { 425b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, media, SUM(size) as filesize 4267428e816SAndreas Gohr FROM media as A 4277428e816SAndreas Gohr WHERE A.dt >= ? AND A.dt <= ? 4287428e816SAndreas Gohr AND mime1 != ? 429b6632b6eSAndreas Gohr GROUP BY media 430b6632b6eSAndreas Gohr ORDER BY cnt DESC, media" . 431f9e60319SAndreas Gohr $this->limit; 432f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'image']); 433b6632b6eSAndreas Gohr } 434b6632b6eSAndreas Gohr 435f9e60319SAndreas Gohr /** 436f9e60319SAndreas Gohr * @return array 437f9e60319SAndreas Gohr */ 438f9e60319SAndreas Gohr public function downloadssum(): array 439b6632b6eSAndreas Gohr { 440b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, SUM(size) as filesize 4417428e816SAndreas Gohr FROM media as A 4427428e816SAndreas Gohr WHERE A.dt >= ? AND A.dt <= ? 4437428e816SAndreas Gohr AND mime1 != ?"; 444f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'image']); 445b6632b6eSAndreas Gohr } 446b6632b6eSAndreas Gohr 447f9e60319SAndreas Gohr /** 448f9e60319SAndreas Gohr * @return array 449f9e60319SAndreas Gohr */ 450f9e60319SAndreas Gohr public function referer(): array 451b6632b6eSAndreas Gohr { 452*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, R.url 453*10dcb86fSAndreas Gohr FROM pageviews as P 454*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 455*10dcb86fSAndreas Gohr LEFT JOIN referers as R ON P.ref_id = R.id 456*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 457*10dcb86fSAndreas Gohr AND S.ua_type = ? 458*10dcb86fSAndreas Gohr AND R.url IS NOT NULL 459*10dcb86fSAndreas Gohr AND R.url != '' 460*10dcb86fSAndreas Gohr AND R.engine IS NULL 461*10dcb86fSAndreas Gohr GROUP BY R.url 462*10dcb86fSAndreas Gohr ORDER BY cnt DESC, R.url" . 463f9e60319SAndreas Gohr $this->limit; 464*10dcb86fSAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'browser']); 465b6632b6eSAndreas Gohr } 466b6632b6eSAndreas Gohr 467f9e60319SAndreas Gohr /** 468f9e60319SAndreas Gohr * @return array 469f9e60319SAndreas Gohr */ 470f9e60319SAndreas Gohr public function newreferer(): array 471b6632b6eSAndreas Gohr { 472*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, R.url 473*10dcb86fSAndreas Gohr FROM pageviews as P 474*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 475*10dcb86fSAndreas Gohr LEFT JOIN referers as R ON P.ref_id = R.id 476*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 477*10dcb86fSAndreas Gohr AND S.ua_type = ? 478*10dcb86fSAndreas Gohr AND R.url IS NOT NULL 479*10dcb86fSAndreas Gohr AND R.url != '' 480*10dcb86fSAndreas Gohr AND R.engine IS NULL 481*10dcb86fSAndreas Gohr AND R.dt >= ? 482*10dcb86fSAndreas Gohr GROUP BY R.url 483*10dcb86fSAndreas Gohr ORDER BY cnt DESC, R.url" . 484f9e60319SAndreas Gohr $this->limit; 485*10dcb86fSAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'browser', $this->from]); 486b6632b6eSAndreas Gohr } 487b6632b6eSAndreas Gohr 488f9e60319SAndreas Gohr /** 489f9e60319SAndreas Gohr * @return array 490f9e60319SAndreas Gohr */ 491f9e60319SAndreas Gohr public function countries(): array 492b6632b6eSAndreas Gohr { 493*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT P.session) as cnt, I.country 494*10dcb86fSAndreas Gohr FROM pageviews as P 495*10dcb86fSAndreas Gohr LEFT JOIN iplocation as I ON P.ip = I.ip 496*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 497*10dcb86fSAndreas Gohr AND I.country IS NOT NULL 498*10dcb86fSAndreas Gohr AND I.country != '' 499*10dcb86fSAndreas Gohr GROUP BY I.code 500*10dcb86fSAndreas Gohr ORDER BY cnt DESC, I.country" . 501f9e60319SAndreas Gohr $this->limit; 502f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to]); 503b6632b6eSAndreas Gohr } 504b6632b6eSAndreas Gohr 505f9e60319SAndreas Gohr /** 506f9e60319SAndreas Gohr * @param bool $ext return extended information 507f9e60319SAndreas Gohr * @return array 508f9e60319SAndreas Gohr */ 509f9e60319SAndreas Gohr public function browsers(bool $ext = true): array 510b6632b6eSAndreas Gohr { 511b6632b6eSAndreas Gohr if ($ext) { 512*10dcb86fSAndreas Gohr $sel = 'S.ua_info as browser, S.ua_ver'; 513*10dcb86fSAndreas Gohr $grp = 'S.ua_info, S.ua_ver'; 514b6632b6eSAndreas Gohr } else { 515*10dcb86fSAndreas Gohr $grp = 'S.ua_info'; 516*10dcb86fSAndreas Gohr $sel = 'S.ua_info'; 517b6632b6eSAndreas Gohr } 518b6632b6eSAndreas Gohr 519*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.session) as cnt, $sel 520*10dcb86fSAndreas Gohr FROM sessions as S 521*10dcb86fSAndreas Gohr WHERE S.dt >= ? AND S.dt <= ? 522*10dcb86fSAndreas Gohr AND S.ua_type = ? 523b6632b6eSAndreas Gohr GROUP BY $grp 524*10dcb86fSAndreas Gohr ORDER BY cnt DESC, S.ua_info" . 525f9e60319SAndreas Gohr $this->limit; 526f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'browser']); 527b6632b6eSAndreas Gohr } 528b6632b6eSAndreas Gohr 529f9e60319SAndreas Gohr /** 530f9e60319SAndreas Gohr * @return array 531f9e60319SAndreas Gohr */ 532f9e60319SAndreas Gohr public function os(): array 533b6632b6eSAndreas Gohr { 534*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.session) as cnt, S.os 535*10dcb86fSAndreas Gohr FROM sessions as S 536*10dcb86fSAndreas Gohr WHERE S.dt >= ? AND S.dt <= ? 537*10dcb86fSAndreas Gohr AND S.ua_type = ? 538*10dcb86fSAndreas Gohr GROUP BY S.os 539*10dcb86fSAndreas Gohr ORDER BY cnt DESC, S.os" . 540f9e60319SAndreas Gohr $this->limit; 541f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'browser']); 542b6632b6eSAndreas Gohr } 543b6632b6eSAndreas Gohr 544f9e60319SAndreas Gohr /** 545f9e60319SAndreas Gohr * @return array 546f9e60319SAndreas Gohr */ 547f9e60319SAndreas Gohr public function topuser(): array 548b6632b6eSAndreas Gohr { 549*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, S.user 550*10dcb86fSAndreas Gohr FROM pageviews as P 551*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 552*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 553*10dcb86fSAndreas Gohr AND S.ua_type = ? 554*10dcb86fSAndreas Gohr AND S.user IS NOT NULL 555*10dcb86fSAndreas Gohr AND S.user != ? 556*10dcb86fSAndreas Gohr GROUP BY S.user 557*10dcb86fSAndreas Gohr ORDER BY cnt DESC, S.user" . 558f9e60319SAndreas Gohr $this->limit; 559f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'browser', '']); 560b6632b6eSAndreas Gohr } 561b6632b6eSAndreas Gohr 562f9e60319SAndreas Gohr /** 563f9e60319SAndreas Gohr * @return array 564f9e60319SAndreas Gohr */ 565f9e60319SAndreas Gohr public function topeditor(): array 566b6632b6eSAndreas Gohr { 567b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, user 568*10dcb86fSAndreas Gohr FROM edits as E 569*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON E.session = S.session 570*10dcb86fSAndreas Gohr WHERE E.dt >= ? AND E.dt <= ? 571*10dcb86fSAndreas Gohr AND S.user != ? 572b6632b6eSAndreas Gohr GROUP BY user 573b6632b6eSAndreas Gohr ORDER BY cnt DESC, user" . 574f9e60319SAndreas Gohr $this->limit; 575f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, '']); 576b6632b6eSAndreas Gohr } 577b6632b6eSAndreas Gohr 578f9e60319SAndreas Gohr /** 579f9e60319SAndreas Gohr * @return array 580f9e60319SAndreas Gohr */ 581f9e60319SAndreas Gohr public function topgroup(): array 582b6632b6eSAndreas Gohr { 583*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, G.`group` 584*10dcb86fSAndreas Gohr FROM pageviews as P 585*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 586*10dcb86fSAndreas Gohr LEFT JOIN groups as G ON S.user = G.user 587*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 588*10dcb86fSAndreas Gohr AND S.ua_type = ? 589*10dcb86fSAndreas Gohr AND G.`group` IS NOT NULL 590*10dcb86fSAndreas Gohr GROUP BY G.`group` 591*10dcb86fSAndreas Gohr ORDER BY cnt DESC, G.`group`" . 592f9e60319SAndreas Gohr $this->limit; 593*10dcb86fSAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'browser']); 594b6632b6eSAndreas Gohr } 595b6632b6eSAndreas Gohr 596f9e60319SAndreas Gohr /** 597f9e60319SAndreas Gohr * @return array 598f9e60319SAndreas Gohr */ 599f9e60319SAndreas Gohr public function topgroupedit(): array 600b6632b6eSAndreas Gohr { 601*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, G.`group` 602*10dcb86fSAndreas Gohr FROM edits as E 603*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON E.session = S.session 604*10dcb86fSAndreas Gohr LEFT JOIN groups as G ON S.user = G.user 605*10dcb86fSAndreas Gohr WHERE E.dt >= ? AND E.dt <= ? 606*10dcb86fSAndreas Gohr AND G.`group` IS NOT NULL 607*10dcb86fSAndreas Gohr GROUP BY G.`group` 608*10dcb86fSAndreas Gohr ORDER BY cnt DESC, G.`group`" . 609f9e60319SAndreas Gohr $this->limit; 610*10dcb86fSAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to]); 611b6632b6eSAndreas Gohr } 612b6632b6eSAndreas Gohr 613b6632b6eSAndreas Gohr 614f9e60319SAndreas Gohr /** 615f9e60319SAndreas Gohr * @return array 616f9e60319SAndreas Gohr */ 617f9e60319SAndreas Gohr public function resolution(): array 618b6632b6eSAndreas Gohr { 619*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.uid) as cnt, 620*10dcb86fSAndreas Gohr ROUND(P.screen_x/100)*100 as res_x, 621*10dcb86fSAndreas Gohr ROUND(P.screen_y/100)*100 as res_y, 622*10dcb86fSAndreas Gohr CAST(ROUND(P.screen_x/100)*100 AS int) || 'x' || CAST(ROUND(P.screen_y/100)*100 AS int) as resolution 623*10dcb86fSAndreas Gohr FROM pageviews as P 624*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 625*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 626*10dcb86fSAndreas Gohr AND S.ua_type = ? 627*10dcb86fSAndreas Gohr AND P.screen_x != ? 628*10dcb86fSAndreas Gohr AND P.screen_y != ? 629b6632b6eSAndreas Gohr GROUP BY resolution 630b6632b6eSAndreas Gohr ORDER BY cnt DESC" . 631f9e60319SAndreas Gohr $this->limit; 632f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'browser', 0, 0]); 633b6632b6eSAndreas Gohr } 634b6632b6eSAndreas Gohr 635f9e60319SAndreas Gohr /** 636f9e60319SAndreas Gohr * @return array 637f9e60319SAndreas Gohr */ 638f9e60319SAndreas Gohr public function viewport(): array 639b6632b6eSAndreas Gohr { 640*10dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.uid) as cnt, 641*10dcb86fSAndreas Gohr ROUND(P.view_x/100)*100 as res_x, 642*10dcb86fSAndreas Gohr ROUND(P.view_y/100)*100 as res_y, 643*10dcb86fSAndreas Gohr CAST(ROUND(P.view_x/100)*100 AS int) || 'x' || CAST(ROUND(P.view_y/100)*100 AS int) as resolution 644*10dcb86fSAndreas Gohr FROM pageviews as P 645*10dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 646*10dcb86fSAndreas Gohr WHERE P.dt >= ? AND P.dt <= ? 647*10dcb86fSAndreas Gohr AND S.ua_type = ? 648*10dcb86fSAndreas Gohr AND P.view_x != ? 649*10dcb86fSAndreas Gohr AND P.view_y != ? 650b6632b6eSAndreas Gohr GROUP BY resolution 651b6632b6eSAndreas Gohr ORDER BY cnt DESC" . 652f9e60319SAndreas Gohr $this->limit; 653b6632b6eSAndreas Gohr 654f9e60319SAndreas Gohr return $this->db->queryAll($sql, [$this->from, $this->to, 'browser', 0, 0]); 655b6632b6eSAndreas Gohr } 656b6632b6eSAndreas Gohr 657f9e60319SAndreas Gohr /** 658f9e60319SAndreas Gohr * @return array 659f9e60319SAndreas Gohr */ 660f9e60319SAndreas Gohr public function seenusers(): array 661b6632b6eSAndreas Gohr { 662*10dcb86fSAndreas Gohr $sql = "SELECT `user`, MAX(`dt`) as dt 663*10dcb86fSAndreas Gohr FROM users 664*10dcb86fSAndreas Gohr WHERE `user` IS NOT NULL 665*10dcb86fSAndreas Gohr AND `user` != '' 666*10dcb86fSAndreas Gohr GROUP BY `user` 667b6632b6eSAndreas Gohr ORDER BY `dt` DESC" . 668f9e60319SAndreas Gohr $this->limit; 669b6632b6eSAndreas Gohr 670f9e60319SAndreas Gohr return $this->db->queryAll($sql); 671b6632b6eSAndreas Gohr } 672b6632b6eSAndreas Gohr} 673