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