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 = ''; 18*44f81330SAndreas Gohr protected string $tz = 'localtime'; 19b6632b6eSAndreas Gohr 20f9e60319SAndreas Gohr /** 21f9e60319SAndreas Gohr * @param helper_plugin_statistics $hlp 22f9e60319SAndreas Gohr */ 23b6632b6eSAndreas Gohr public function __construct(helper_plugin_statistics $hlp) 24b6632b6eSAndreas Gohr { 25b6632b6eSAndreas Gohr $this->hlp = $hlp; 26f9e60319SAndreas Gohr $this->db = $hlp->getDB(); 277428e816SAndreas Gohr $today = date('Y-m-d'); 287428e816SAndreas Gohr $this->setTimeFrame($today, $today); 29f9e60319SAndreas Gohr $this->setPagination(0, 20); 307428e816SAndreas Gohr } 317428e816SAndreas Gohr 327428e816SAndreas Gohr /** 337428e816SAndreas Gohr * Set the time frame for all queries 34f9e60319SAndreas Gohr * 35f9e60319SAndreas Gohr * @param string $from The start date as YYYY-MM-DD 36f9e60319SAndreas Gohr * @param string $to The end date as YYYY-MM-DD 377428e816SAndreas Gohr */ 38f9e60319SAndreas Gohr public function setTimeFrame(string $from, string $to): void 397428e816SAndreas Gohr { 40f9e60319SAndreas Gohr try { 41f9e60319SAndreas Gohr $from = new \DateTime($from); 42f9e60319SAndreas Gohr $to = new \DateTime($to); 43f9e60319SAndreas Gohr } catch (\Exception $e) { 44f9e60319SAndreas Gohr $from = new \DateTime(); 45f9e60319SAndreas Gohr $to = new \DateTime(); 46f9e60319SAndreas Gohr } 47f9e60319SAndreas Gohr $from->setTime(0, 0); 48f9e60319SAndreas Gohr $to->setTime(23, 59, 59); 497428e816SAndreas Gohr 50f9e60319SAndreas Gohr $this->from = $from->format('Y-m-d H:i:s'); 51f9e60319SAndreas Gohr $this->to = $to->format('Y-m-d H:i:s'); 52f9e60319SAndreas Gohr } 53f9e60319SAndreas Gohr 54f9e60319SAndreas Gohr /** 55f9e60319SAndreas Gohr * Set the pagination settings for some queries 56f9e60319SAndreas Gohr * 57f9e60319SAndreas Gohr * @param int $start The start offset 58f9e60319SAndreas Gohr * @param int $limit The number of results. If one more is returned, there is another page 59f9e60319SAndreas Gohr * @return void 60f9e60319SAndreas Gohr */ 61f9e60319SAndreas Gohr public function setPagination(int $start, int $limit) 62f9e60319SAndreas Gohr { 63f9e60319SAndreas Gohr // when a limit is set, one more is fetched to indicate when a next page exists 64f9e60319SAndreas Gohr if ($limit) $limit += 1; 65f9e60319SAndreas Gohr 66f9e60319SAndreas Gohr if ($limit) { 67f9e60319SAndreas Gohr $this->limit = " LIMIT $start,$limit"; 68f9e60319SAndreas Gohr } elseif ($start) { 69f9e60319SAndreas Gohr $this->limit = " OFFSET $start"; 70f9e60319SAndreas Gohr } 71b6632b6eSAndreas Gohr } 72b6632b6eSAndreas Gohr 73b6632b6eSAndreas Gohr /** 74b6632b6eSAndreas Gohr * Return some aggregated statistics 75b6632b6eSAndreas Gohr */ 76f9e60319SAndreas Gohr public function aggregate(): array 77b6632b6eSAndreas Gohr { 782a30f557SAndreas Gohr // init some values that might not be set 792a30f557SAndreas Gohr $data = [ 802a30f557SAndreas Gohr 'referers' => 0, // total number of (external) referrers 812a30f557SAndreas Gohr 'external' => 0, // external referrers 822a30f557SAndreas Gohr 'search' => 0, // search engine referrers 832a30f557SAndreas Gohr 'direct' => 0, // direct referrers 842a30f557SAndreas Gohr 'internal' => 0, // internal referrers 852a30f557SAndreas Gohr 'bouncerate' => 0, 862a30f557SAndreas Gohr 'newvisitors' => 0, 872a30f557SAndreas Gohr ]; 88b6632b6eSAndreas Gohr 8910dcb86fSAndreas Gohr // Count referrer types by joining with referers table 9010dcb86fSAndreas Gohr $sql = "SELECT 9110dcb86fSAndreas Gohr CASE 9210dcb86fSAndreas Gohr WHEN R.engine IS NOT NULL THEN 'search' 932a30f557SAndreas Gohr WHEN R.url = '' THEN 'direct' 942a30f557SAndreas Gohr WHEN R.url IS NOT NULL THEN 'external' 952a30f557SAndreas Gohr ELSE 'internal' 9610dcb86fSAndreas Gohr END as ref_type, 9710dcb86fSAndreas Gohr COUNT(*) as cnt 9810dcb86fSAndreas Gohr FROM pageviews as P 9910dcb86fSAndreas Gohr LEFT JOIN referers as R ON P.ref_id = R.id 10010dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 101*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 10230cf9434SAndreas Gohr AND S.ua_type = 'browser' 103b6632b6eSAndreas Gohr GROUP BY ref_type"; 104*44f81330SAndreas Gohr $result = $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 105b6632b6eSAndreas Gohr 106f9e60319SAndreas Gohr foreach ($result as $row) { 1072a30f557SAndreas Gohr if ($row['ref_type'] == 'search') { 1082a30f557SAndreas Gohr $data['search'] = $row['cnt']; 1092a30f557SAndreas Gohr $data['referers'] += $row['cnt']; 1102a30f557SAndreas Gohr } 1112a30f557SAndreas Gohr if ($row['ref_type'] == 'direct') { 1122a30f557SAndreas Gohr $data['direct'] = $row['cnt']; 1132a30f557SAndreas Gohr $data['referers'] += $row['cnt']; 1142a30f557SAndreas Gohr } 1152a30f557SAndreas Gohr if ($row['ref_type'] == 'external') { 1162a30f557SAndreas Gohr $data['external'] = $row['cnt']; 1172a30f557SAndreas Gohr $data['referers'] += $row['cnt']; 1182a30f557SAndreas Gohr } 1192a30f557SAndreas Gohr if ($row['ref_type'] == 'internal') { 1202a30f557SAndreas Gohr $data['internal'] = $row['cnt']; 1212a30f557SAndreas Gohr } 122b6632b6eSAndreas Gohr } 123b6632b6eSAndreas Gohr 124b6632b6eSAndreas Gohr // general user and session info 12510dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT P.session) as sessions, 12610dcb86fSAndreas Gohr COUNT(P.session) as views, 12710dcb86fSAndreas Gohr COUNT(DISTINCT S.user) as users, 128*44f81330SAndreas Gohr COUNT(DISTINCT S.uid) as visitors, 129*44f81330SAndreas Gohr DATETIME(MAX(P.dt), ?) as last 13010dcb86fSAndreas Gohr FROM pageviews as P 13110dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 132*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 13330cf9434SAndreas Gohr AND S.ua_type = 'browser'"; 134*44f81330SAndreas Gohr $result = $this->db->queryRecord($sql, [$this->tz, $this->tz, $this->from, $this->tz, $this->to]); 135b6632b6eSAndreas Gohr 13610dcb86fSAndreas Gohr $data['users'] = $result['users']; 137f9e60319SAndreas Gohr $data['sessions'] = $result['sessions']; 138f9e60319SAndreas Gohr $data['pageviews'] = $result['views']; 139f9e60319SAndreas Gohr $data['visitors'] = $result['visitors']; 140*44f81330SAndreas Gohr $data['last'] = $result['last']; 141b6632b6eSAndreas Gohr 14210dcb86fSAndreas Gohr // calculate bounce rate (sessions with only 1 page view) 143b6632b6eSAndreas Gohr if ($data['sessions']) { 144b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt 14510dcb86fSAndreas Gohr FROM ( 14610dcb86fSAndreas Gohr SELECT P.session, COUNT(*) as views 14710dcb86fSAndreas Gohr FROM pageviews as P 14810dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 149*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 15030cf9434SAndreas Gohr AND S.ua_type = 'browser' 15110dcb86fSAndreas Gohr GROUP BY P.session 15210dcb86fSAndreas Gohr HAVING views = 1 15310dcb86fSAndreas Gohr )"; 154*44f81330SAndreas Gohr $count = $this->db->queryValue($sql, [$this->tz, $this->from, $this->tz, $this->to]); 155f9e60319SAndreas Gohr $data['bouncerate'] = $count * 100 / $data['sessions']; 156f9e60319SAndreas Gohr $data['newvisitors'] = $count * 100 / $data['sessions']; 157b6632b6eSAndreas Gohr } 158b6632b6eSAndreas Gohr 159b6632b6eSAndreas Gohr // calculate avg. number of views per session 160b6632b6eSAndreas Gohr $sql = "SELECT AVG(views) as cnt 16110dcb86fSAndreas Gohr FROM ( 16210dcb86fSAndreas Gohr SELECT P.session, COUNT(*) as views 16310dcb86fSAndreas Gohr FROM pageviews as P 16410dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 165*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 16630cf9434SAndreas Gohr AND S.ua_type = 'browser' 16710dcb86fSAndreas Gohr GROUP BY P.session 16810dcb86fSAndreas Gohr )"; 169*44f81330SAndreas Gohr $data['avgpages'] = $this->db->queryValue($sql, [$this->tz, $this->from, $this->tz, $this->to]); 170b6632b6eSAndreas Gohr 171b6632b6eSAndreas Gohr // average time spent on the site 17210dcb86fSAndreas Gohr $sql = "SELECT AVG((julianday(end) - julianday(dt)) * 24 * 60) as time 17310dcb86fSAndreas Gohr FROM sessions as S 17410dcb86fSAndreas Gohr WHERE S.dt >= ? AND S.dt <= ? 17510dcb86fSAndreas Gohr AND S.dt != S.end 176*44f81330SAndreas Gohr AND DATETIME(S.dt, ?) >= ? AND DATETIME(S.dt, ?) <= ? 17730cf9434SAndreas Gohr AND S.ua_type = 'browser'"; 178*44f81330SAndreas Gohr $data['timespent'] = $this->db->queryValue($sql, [$this->tz, $this->from, $this->tz, $this->to]); 179b6632b6eSAndreas Gohr 180b6632b6eSAndreas Gohr // logins 181b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as logins 1827428e816SAndreas Gohr FROM logins as A 183*44f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 18430cf9434SAndreas Gohr AND (type = 'l' OR type = 'p')"; 185*44f81330SAndreas Gohr $data['logins'] = $this->db->queryValue($sql, [$this->tz, $this->from, $this->tz, $this->to]); 186b6632b6eSAndreas Gohr 187b6632b6eSAndreas Gohr // registrations 188b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as registrations 1897428e816SAndreas Gohr FROM logins as A 190*44f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 19130cf9434SAndreas Gohr AND type = 'C'"; 192*44f81330SAndreas Gohr $data['registrations'] = $this->db->queryValue($sql, [$this->tz, $this->from, $this->tz, $this->to]); 193b6632b6eSAndreas Gohr 19410dcb86fSAndreas Gohr // current users (based on recent sessions) 19510dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT uid) as current 19610dcb86fSAndreas Gohr FROM sessions 19710dcb86fSAndreas Gohr WHERE end >= datetime('now', '-10 minutes')"; 198f9e60319SAndreas Gohr $data['current'] = $this->db->queryValue($sql); 199b6632b6eSAndreas Gohr 200b6632b6eSAndreas Gohr return $data; 201b6632b6eSAndreas Gohr } 202b6632b6eSAndreas Gohr 203b6632b6eSAndreas Gohr 204b6632b6eSAndreas Gohr /** 205b6632b6eSAndreas Gohr * Return some trend data about visits and edits in the wiki 206f9e60319SAndreas Gohr * 207f9e60319SAndreas Gohr * @param bool $hours Use hour resolution rather than days 208f9e60319SAndreas Gohr * @return array 209b6632b6eSAndreas Gohr */ 210f9e60319SAndreas Gohr public function dashboardviews(bool $hours = false): array 211b6632b6eSAndreas Gohr { 212b6632b6eSAndreas Gohr if ($hours) { 213*44f81330SAndreas Gohr $TIME = "strftime('%H', DATETIME(P.dt, '$this->tz'))"; 214b6632b6eSAndreas Gohr } else { 215*44f81330SAndreas Gohr $TIME = "DATE(DATETIME(P.dt, '$this->tz'))"; 216b6632b6eSAndreas Gohr } 217b6632b6eSAndreas Gohr 218b6632b6eSAndreas Gohr $data = []; 219b6632b6eSAndreas Gohr 220b6632b6eSAndreas Gohr // access trends 221b6632b6eSAndreas Gohr $sql = "SELECT $TIME as time, 22210dcb86fSAndreas Gohr COUNT(DISTINCT P.session) as sessions, 22310dcb86fSAndreas Gohr COUNT(P.session) as pageviews, 22410dcb86fSAndreas Gohr COUNT(DISTINCT S.uid) as visitors 22510dcb86fSAndreas Gohr FROM pageviews as P 22610dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 227*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 22830cf9434SAndreas Gohr AND S.ua_type = 'browser' 229b6632b6eSAndreas Gohr GROUP BY $TIME 230b6632b6eSAndreas Gohr ORDER BY time"; 231*44f81330SAndreas Gohr $result = $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 232b6632b6eSAndreas Gohr foreach ($result as $row) { 233b6632b6eSAndreas Gohr $data[$row['time']]['sessions'] = $row['sessions']; 234b6632b6eSAndreas Gohr $data[$row['time']]['pageviews'] = $row['pageviews']; 235b6632b6eSAndreas Gohr $data[$row['time']]['visitors'] = $row['visitors']; 236b6632b6eSAndreas Gohr } 237b6632b6eSAndreas Gohr return $data; 238b6632b6eSAndreas Gohr } 239b6632b6eSAndreas Gohr 240f9e60319SAndreas Gohr /** 241f9e60319SAndreas Gohr * @param bool $hours Use hour resolution rather than days 242f9e60319SAndreas Gohr * @return array 243f9e60319SAndreas Gohr */ 244f9e60319SAndreas Gohr public function dashboardwiki(bool $hours = false): array 245b6632b6eSAndreas Gohr { 246b6632b6eSAndreas Gohr if ($hours) { 247*44f81330SAndreas Gohr $TIME = "strftime('%H', DATETIME(dt, '$this->tz'))"; 248b6632b6eSAndreas Gohr } else { 249*44f81330SAndreas Gohr $TIME = "DATE(DATETIME(dt, '$this->tz'))"; 250b6632b6eSAndreas Gohr } 251b6632b6eSAndreas Gohr 252b6632b6eSAndreas Gohr $data = []; 253b6632b6eSAndreas Gohr 254b6632b6eSAndreas Gohr // edit trends 255b6632b6eSAndreas Gohr foreach (['E', 'C', 'D'] as $type) { 256b6632b6eSAndreas Gohr $sql = "SELECT $TIME as time, 257b6632b6eSAndreas Gohr COUNT(*) as cnt 2587428e816SAndreas Gohr FROM edits as A 259*44f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 26030cf9434SAndreas Gohr AND type = '$type' 261b6632b6eSAndreas Gohr GROUP BY $TIME 262b6632b6eSAndreas Gohr ORDER BY time"; 263*44f81330SAndreas Gohr $result = $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 264b6632b6eSAndreas Gohr foreach ($result as $row) { 265b6632b6eSAndreas Gohr $data[$row['time']][$type] = $row['cnt']; 266b6632b6eSAndreas Gohr } 267b6632b6eSAndreas Gohr } 268b6632b6eSAndreas Gohr ksort($data); 269b6632b6eSAndreas Gohr return $data; 270b6632b6eSAndreas Gohr } 271b6632b6eSAndreas Gohr 272f9e60319SAndreas Gohr /** 273f9e60319SAndreas Gohr * @param string $info Which type of history to select (FIXME which ones are there?) 274f9e60319SAndreas Gohr * @param string $interval Group data by this interval (days, weeks, months) 275f9e60319SAndreas Gohr * @return array 276f9e60319SAndreas Gohr */ 277f9e60319SAndreas Gohr public function history(string $info, string $interval = 'day'): array 278b6632b6eSAndreas Gohr { 279b6632b6eSAndreas Gohr if ($interval == 'weeks') { 280*44f81330SAndreas Gohr $TIME = "strftime('%Y', DATETIME(dt, '$this->tz')), strftime('%W', DATETIME(dt, '$this->tz'))"; 281b6632b6eSAndreas Gohr } elseif ($interval == 'months') { 282*44f81330SAndreas Gohr $TIME = "strftime('%Y-%m', DATETIME(dt, '$this->tz'))"; 283b6632b6eSAndreas Gohr } else { 284*44f81330SAndreas Gohr $TIME = "strftime('%d-%m', DATETIME(dt, '$this->tz'))"; 285b6632b6eSAndreas Gohr } 286b6632b6eSAndreas Gohr 287b6632b6eSAndreas Gohr $mod = 1; 288b6632b6eSAndreas Gohr if ($info == 'media_size' || $info == 'page_size') { 289b6632b6eSAndreas Gohr $mod = 1024 * 1024; 290b6632b6eSAndreas Gohr } 291b6632b6eSAndreas Gohr 292b6632b6eSAndreas Gohr $sql = "SELECT $TIME as time, 2937428e816SAndreas Gohr AVG(value)/$mod as cnt 2947428e816SAndreas Gohr FROM history as A 295*44f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 2967428e816SAndreas Gohr AND info = ? 297b6632b6eSAndreas Gohr GROUP BY $TIME 298b6632b6eSAndreas Gohr ORDER BY $TIME"; 299*44f81330SAndreas Gohr 300*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to, $info]); 301b6632b6eSAndreas Gohr } 302b6632b6eSAndreas Gohr 303f9e60319SAndreas Gohr /** 304f9e60319SAndreas Gohr * @return array 305f9e60319SAndreas Gohr */ 306f9e60319SAndreas Gohr public function searchengines(): array 307b6632b6eSAndreas Gohr { 30810dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, R.engine 3096f2bdce1SAndreas Gohr FROM pageviews as P, 3106f2bdce1SAndreas Gohr referers as R 311*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 3126f2bdce1SAndreas Gohr AND P.ref_id = R.id 31310dcb86fSAndreas Gohr AND R.engine != '' 31410dcb86fSAndreas Gohr GROUP BY R.engine 31510dcb86fSAndreas Gohr ORDER BY cnt DESC, R.engine" . 316f9e60319SAndreas Gohr $this->limit; 317*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 318b6632b6eSAndreas Gohr } 319b6632b6eSAndreas Gohr 320f9e60319SAndreas Gohr /** 321f9e60319SAndreas Gohr * @return array 322f9e60319SAndreas Gohr */ 3232a30f557SAndreas Gohr public function searchphrases(): array 324b6632b6eSAndreas Gohr { 3252a30f557SAndreas Gohr $sql = "SELECT COUNT(*) as cnt, query, query as ilookup 3262a30f557SAndreas Gohr FROM search 327*44f81330SAndreas Gohr WHERE DATETIME(dt, ?) >= ? AND DATETIME(dt, ?) <= ? 3282a30f557SAndreas Gohr GROUP BY query 3292a30f557SAndreas Gohr ORDER BY cnt DESC, query" . 330f9e60319SAndreas Gohr $this->limit; 331*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 332b6632b6eSAndreas Gohr } 333b6632b6eSAndreas Gohr 334f9e60319SAndreas Gohr /** 335f9e60319SAndreas Gohr * @return array 336f9e60319SAndreas Gohr */ 3372a30f557SAndreas Gohr public function searchwords(): array 338b6632b6eSAndreas Gohr { 3392a30f557SAndreas Gohr $sql = "SELECT COUNT(*) as cnt, SW.word, SW.word as ilookup 3402a30f557SAndreas Gohr FROM search as S, 3412a30f557SAndreas Gohr searchwords as SW 342*44f81330SAndreas Gohr WHERE DATETIME(S.dt, ?) >= ? AND DATETIME(S.dt, ?) <= ? 3432a30f557SAndreas Gohr AND S.id = SW.sid 34410dcb86fSAndreas Gohr GROUP BY SW.word 34510dcb86fSAndreas Gohr ORDER BY cnt DESC, SW.word" . 346f9e60319SAndreas Gohr $this->limit; 347*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 348b6632b6eSAndreas Gohr } 349b6632b6eSAndreas Gohr 350f9e60319SAndreas Gohr /** 351f9e60319SAndreas Gohr * @return array 352f9e60319SAndreas Gohr */ 353f9e60319SAndreas Gohr public function outlinks(): array 354b6632b6eSAndreas Gohr { 355b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, link as url 3567428e816SAndreas Gohr FROM outlinks as A 357*44f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 358b6632b6eSAndreas Gohr GROUP BY link 359b6632b6eSAndreas Gohr ORDER BY cnt DESC, link" . 360f9e60319SAndreas Gohr $this->limit; 361*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 362b6632b6eSAndreas Gohr } 363b6632b6eSAndreas Gohr 364f9e60319SAndreas Gohr /** 365f9e60319SAndreas Gohr * @return array 366f9e60319SAndreas Gohr */ 367f9e60319SAndreas Gohr public function pages(): array 368b6632b6eSAndreas Gohr { 36910dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, P.page 3706f2bdce1SAndreas Gohr FROM pageviews as P, 3716f2bdce1SAndreas Gohr sessions as S 372*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 3736f2bdce1SAndreas Gohr AND P.session = S.session 37430cf9434SAndreas Gohr AND S.ua_type = 'browser' 37510dcb86fSAndreas Gohr GROUP BY P.page 37610dcb86fSAndreas Gohr ORDER BY cnt DESC, P.page" . 377f9e60319SAndreas Gohr $this->limit; 378*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 379b6632b6eSAndreas Gohr } 380b6632b6eSAndreas Gohr 381f9e60319SAndreas Gohr /** 382f9e60319SAndreas Gohr * @return array 383f9e60319SAndreas Gohr */ 384f9e60319SAndreas Gohr public function edits(): array 385b6632b6eSAndreas Gohr { 386b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, page 3877428e816SAndreas Gohr FROM edits as A 388*44f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 389b6632b6eSAndreas Gohr GROUP BY page 390b6632b6eSAndreas Gohr ORDER BY cnt DESC, page" . 391f9e60319SAndreas Gohr $this->limit; 392*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 393b6632b6eSAndreas Gohr } 394b6632b6eSAndreas Gohr 395f9e60319SAndreas Gohr /** 396f9e60319SAndreas Gohr * @return array 397f9e60319SAndreas Gohr */ 398f9e60319SAndreas Gohr public function images(): array 399b6632b6eSAndreas Gohr { 400b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, media, SUM(size) as filesize 4017428e816SAndreas Gohr FROM media as A 402*44f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 40330cf9434SAndreas Gohr AND mime1 = 'image' 404b6632b6eSAndreas Gohr GROUP BY media 405b6632b6eSAndreas Gohr ORDER BY cnt DESC, media" . 406f9e60319SAndreas Gohr $this->limit; 407*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 408b6632b6eSAndreas Gohr } 409b6632b6eSAndreas Gohr 410f9e60319SAndreas Gohr /** 411f9e60319SAndreas Gohr * @return array 412f9e60319SAndreas Gohr */ 413f9e60319SAndreas Gohr public function imagessum(): array 414b6632b6eSAndreas Gohr { 415b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, SUM(size) as filesize 4167428e816SAndreas Gohr FROM media as A 417*44f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 41830cf9434SAndreas Gohr AND mime1 = 'image'"; 419*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 420b6632b6eSAndreas Gohr } 421b6632b6eSAndreas Gohr 422f9e60319SAndreas Gohr /** 423f9e60319SAndreas Gohr * @return array 424f9e60319SAndreas Gohr */ 425f9e60319SAndreas Gohr public function downloads(): array 426b6632b6eSAndreas Gohr { 427b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, media, SUM(size) as filesize 4287428e816SAndreas Gohr FROM media as A 429*44f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 43030cf9434SAndreas Gohr AND mime1 != 'image' 431b6632b6eSAndreas Gohr GROUP BY media 432b6632b6eSAndreas Gohr ORDER BY cnt DESC, media" . 433f9e60319SAndreas Gohr $this->limit; 434*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 435b6632b6eSAndreas Gohr } 436b6632b6eSAndreas Gohr 437f9e60319SAndreas Gohr /** 438f9e60319SAndreas Gohr * @return array 439f9e60319SAndreas Gohr */ 440f9e60319SAndreas Gohr public function downloadssum(): array 441b6632b6eSAndreas Gohr { 442b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, SUM(size) as filesize 4437428e816SAndreas Gohr FROM media as A 444*44f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 44530cf9434SAndreas Gohr AND mime1 != 'image'"; 446*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 447b6632b6eSAndreas Gohr } 448b6632b6eSAndreas Gohr 449f9e60319SAndreas Gohr /** 450f9e60319SAndreas Gohr * @return array 451f9e60319SAndreas Gohr */ 452f9e60319SAndreas Gohr public function referer(): array 453b6632b6eSAndreas Gohr { 45410dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, R.url 45510dcb86fSAndreas Gohr FROM pageviews as P 45610dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 45710dcb86fSAndreas Gohr LEFT JOIN referers as R ON P.ref_id = R.id 458*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 45930cf9434SAndreas Gohr AND S.ua_type = 'browser' 46010dcb86fSAndreas Gohr AND R.url IS NOT NULL 46110dcb86fSAndreas Gohr AND R.url != '' 46210dcb86fSAndreas Gohr AND R.engine IS NULL 46310dcb86fSAndreas Gohr GROUP BY R.url 46410dcb86fSAndreas Gohr ORDER BY cnt DESC, R.url" . 465f9e60319SAndreas Gohr $this->limit; 466*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 467b6632b6eSAndreas Gohr } 468b6632b6eSAndreas Gohr 469f9e60319SAndreas Gohr /** 470f9e60319SAndreas Gohr * @return array 471f9e60319SAndreas Gohr */ 472f9e60319SAndreas Gohr public function newreferer(): array 473b6632b6eSAndreas Gohr { 47410dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, R.url 47510dcb86fSAndreas Gohr FROM pageviews as P 47610dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 47710dcb86fSAndreas Gohr LEFT JOIN referers as R ON P.ref_id = R.id 478*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 47930cf9434SAndreas Gohr AND S.ua_type = 'browser' 48010dcb86fSAndreas Gohr AND R.url IS NOT NULL 48110dcb86fSAndreas Gohr AND R.url != '' 48210dcb86fSAndreas Gohr AND R.engine IS NULL 483*44f81330SAndreas Gohr AND DATETIME(R.dt, ?) >= ? 48410dcb86fSAndreas Gohr GROUP BY R.url 48510dcb86fSAndreas Gohr ORDER BY cnt DESC, R.url" . 486f9e60319SAndreas Gohr $this->limit; 487*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to, $this->tz, $this->from]); 488b6632b6eSAndreas Gohr } 489b6632b6eSAndreas Gohr 490f9e60319SAndreas Gohr /** 491f9e60319SAndreas Gohr * @return array 492f9e60319SAndreas Gohr */ 493f9e60319SAndreas Gohr public function countries(): array 494b6632b6eSAndreas Gohr { 49510dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT P.session) as cnt, I.country 4966f2bdce1SAndreas Gohr FROM pageviews as P, 4976f2bdce1SAndreas Gohr iplocation as I 498*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 4996f2bdce1SAndreas Gohr AND P.ip = I.ip 50010dcb86fSAndreas Gohr AND I.country != '' 50110dcb86fSAndreas Gohr GROUP BY I.code 50210dcb86fSAndreas Gohr ORDER BY cnt DESC, I.country" . 503f9e60319SAndreas Gohr $this->limit; 504*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 505b6632b6eSAndreas Gohr } 506b6632b6eSAndreas Gohr 507f9e60319SAndreas Gohr /** 508f9e60319SAndreas Gohr * @param bool $ext return extended information 509f9e60319SAndreas Gohr * @return array 510f9e60319SAndreas Gohr */ 5112a30f557SAndreas Gohr public function browsers(bool $ext = false): array 512b6632b6eSAndreas Gohr { 513b6632b6eSAndreas Gohr if ($ext) { 51410dcb86fSAndreas Gohr $sel = 'S.ua_info as browser, S.ua_ver'; 51510dcb86fSAndreas Gohr $grp = 'S.ua_info, S.ua_ver'; 516b6632b6eSAndreas Gohr } else { 5172a30f557SAndreas Gohr $sel = 'S.ua_info as browser'; 51810dcb86fSAndreas Gohr $grp = 'S.ua_info'; 519b6632b6eSAndreas Gohr } 520b6632b6eSAndreas Gohr 52110dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.session) as cnt, $sel 52210dcb86fSAndreas Gohr FROM sessions as S 523*44f81330SAndreas Gohr WHERE DATETIME(S.dt, ?) >= ? AND DATETIME(S.dt, ?) <= ? 52430cf9434SAndreas Gohr AND S.ua_type = 'browser' 525b6632b6eSAndreas Gohr GROUP BY $grp 52610dcb86fSAndreas Gohr ORDER BY cnt DESC, S.ua_info" . 527f9e60319SAndreas Gohr $this->limit; 528*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 529b6632b6eSAndreas Gohr } 530b6632b6eSAndreas Gohr 531f9e60319SAndreas Gohr /** 532f9e60319SAndreas Gohr * @return array 533f9e60319SAndreas Gohr */ 534f9e60319SAndreas Gohr public function os(): array 535b6632b6eSAndreas Gohr { 53610dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.session) as cnt, S.os 53710dcb86fSAndreas Gohr FROM sessions as S 538*44f81330SAndreas Gohr WHERE DATETIME(S.dt, ?) >= ? AND DATETIME(S.dt, ?) <= ? 53930cf9434SAndreas Gohr AND S.ua_type = 'browser' 54010dcb86fSAndreas Gohr GROUP BY S.os 54110dcb86fSAndreas Gohr ORDER BY cnt DESC, S.os" . 542f9e60319SAndreas Gohr $this->limit; 543*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 544b6632b6eSAndreas Gohr } 545b6632b6eSAndreas Gohr 546f9e60319SAndreas Gohr /** 547f9e60319SAndreas Gohr * @return array 548f9e60319SAndreas Gohr */ 5499fdd7e51SAndreas Gohr public function topdomain(): array 5509fdd7e51SAndreas Gohr { 5519fdd7e51SAndreas Gohr $sql = "SELECT COUNT(*) as cnt, U.domain 5529fdd7e51SAndreas Gohr FROM pageviews as P, 5539fdd7e51SAndreas Gohr sessions as S, 5549fdd7e51SAndreas Gohr users as U 555*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 5569fdd7e51SAndreas Gohr AND P.session = S.session 5579fdd7e51SAndreas Gohr AND S.user = U.user 55830cf9434SAndreas Gohr AND S.ua_type = 'browser' 5599fdd7e51SAndreas Gohr AND S.user IS NOT NULL 5609fdd7e51SAndreas Gohr GROUP BY U.domain 5619fdd7e51SAndreas Gohr ORDER BY cnt DESC, U.domain" . 5629fdd7e51SAndreas Gohr $this->limit; 563*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 5649fdd7e51SAndreas Gohr } 5659fdd7e51SAndreas Gohr 5669fdd7e51SAndreas Gohr /** 5679fdd7e51SAndreas Gohr * @return array 5689fdd7e51SAndreas Gohr */ 569f9e60319SAndreas Gohr public function topuser(): array 570b6632b6eSAndreas Gohr { 57110dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, S.user 5726f2bdce1SAndreas Gohr FROM pageviews as P, 5736f2bdce1SAndreas Gohr sessions as S 574*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 5756f2bdce1SAndreas Gohr AND P.session = S.session 57630cf9434SAndreas Gohr AND S.ua_type = 'browser' 577b7091bfdSAndreas Gohr AND S.user IS NOT NULL 57810dcb86fSAndreas Gohr GROUP BY S.user 57910dcb86fSAndreas Gohr ORDER BY cnt DESC, S.user" . 580f9e60319SAndreas Gohr $this->limit; 581*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 582b6632b6eSAndreas Gohr } 583b6632b6eSAndreas Gohr 584f9e60319SAndreas Gohr /** 585f9e60319SAndreas Gohr * @return array 586f9e60319SAndreas Gohr */ 587f9e60319SAndreas Gohr public function topeditor(): array 588b6632b6eSAndreas Gohr { 589b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, user 5906f2bdce1SAndreas Gohr FROM edits as E, 5916f2bdce1SAndreas Gohr sessions as S 592*44f81330SAndreas Gohr WHERE DATETIME(E.dt, ?) >= ? AND DATETIME(E.dt, ?) <= ? 5936f2bdce1SAndreas Gohr AND E.session = S.session 594b7091bfdSAndreas Gohr AND S.user IS NOT NULL 595b6632b6eSAndreas Gohr GROUP BY user 596b6632b6eSAndreas Gohr ORDER BY cnt DESC, user" . 597f9e60319SAndreas Gohr $this->limit; 598*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 599b6632b6eSAndreas Gohr } 600b6632b6eSAndreas Gohr 601f9e60319SAndreas Gohr /** 602f9e60319SAndreas Gohr * @return array 603f9e60319SAndreas Gohr */ 604f9e60319SAndreas Gohr public function topgroup(): array 605b6632b6eSAndreas Gohr { 60610dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, G.`group` 6076f2bdce1SAndreas Gohr FROM pageviews as P, 6086f2bdce1SAndreas Gohr sessions as S, 6096f2bdce1SAndreas Gohr groups as G 610*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 6116f2bdce1SAndreas Gohr AND P.session = S.session 6126f2bdce1SAndreas Gohr AND S.user = G.user 61330cf9434SAndreas Gohr AND S.ua_type = 'browser' 61410dcb86fSAndreas Gohr GROUP BY G.`group` 61510dcb86fSAndreas Gohr ORDER BY cnt DESC, G.`group`" . 616f9e60319SAndreas Gohr $this->limit; 617*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 618b6632b6eSAndreas Gohr } 619b6632b6eSAndreas Gohr 620f9e60319SAndreas Gohr /** 621f9e60319SAndreas Gohr * @return array 622f9e60319SAndreas Gohr */ 623f9e60319SAndreas Gohr public function topgroupedit(): array 624b6632b6eSAndreas Gohr { 62510dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, G.`group` 6266f2bdce1SAndreas Gohr FROM edits as E, 6276f2bdce1SAndreas Gohr sessions as S, 6286f2bdce1SAndreas Gohr groups as G 629*44f81330SAndreas Gohr WHERE DATETIME(E.dt, ?) >= ? AND DATETIME(E.dt, ?) <= ? 6306f2bdce1SAndreas Gohr AND E.session = S.session 6316f2bdce1SAndreas Gohr AND S.user = G.user 63210dcb86fSAndreas Gohr GROUP BY G.`group` 63310dcb86fSAndreas Gohr ORDER BY cnt DESC, G.`group`" . 634f9e60319SAndreas Gohr $this->limit; 635*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 636b6632b6eSAndreas Gohr } 637b6632b6eSAndreas Gohr 638b6632b6eSAndreas Gohr 639f9e60319SAndreas Gohr /** 640f9e60319SAndreas Gohr * @return array 641f9e60319SAndreas Gohr */ 642f9e60319SAndreas Gohr public function resolution(): array 643b6632b6eSAndreas Gohr { 64410dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.uid) as cnt, 64510dcb86fSAndreas Gohr ROUND(P.screen_x/100)*100 as res_x, 64610dcb86fSAndreas Gohr ROUND(P.screen_y/100)*100 as res_y, 647bd514593SAndreas Gohr CAST(ROUND(P.screen_x/100)*100 AS int) 648bd514593SAndreas Gohr || 'x' || 649bd514593SAndreas Gohr CAST(ROUND(P.screen_y/100)*100 AS int) as resolution 6506f2bdce1SAndreas Gohr FROM pageviews as P, 6516f2bdce1SAndreas Gohr sessions as S 652*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 6536f2bdce1SAndreas Gohr AND P.session = S.session 65430cf9434SAndreas Gohr AND S.ua_type = 'browser' 65530cf9434SAndreas Gohr AND P.screen_x != 0 65630cf9434SAndreas Gohr AND P.screen_y != 0 657b6632b6eSAndreas Gohr GROUP BY resolution 658b6632b6eSAndreas Gohr ORDER BY cnt DESC" . 659f9e60319SAndreas Gohr $this->limit; 660*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 661b6632b6eSAndreas Gohr } 662b6632b6eSAndreas Gohr 663f9e60319SAndreas Gohr /** 664f9e60319SAndreas Gohr * @return array 665f9e60319SAndreas Gohr */ 666f9e60319SAndreas Gohr public function viewport(): array 667b6632b6eSAndreas Gohr { 66810dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.uid) as cnt, 66910dcb86fSAndreas Gohr ROUND(P.view_x/100)*100 as res_x, 67010dcb86fSAndreas Gohr ROUND(P.view_y/100)*100 as res_y, 671bd514593SAndreas Gohr CAST(ROUND(P.view_x/100)*100 AS int) 672bd514593SAndreas Gohr || 'x' || 673bd514593SAndreas Gohr CAST(ROUND(P.view_y/100)*100 AS int) as resolution 6746f2bdce1SAndreas Gohr FROM pageviews as P, 6756f2bdce1SAndreas Gohr sessions as S 676*44f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 6776f2bdce1SAndreas Gohr AND P.session = S.session 67830cf9434SAndreas Gohr AND S.ua_type = 'browser' 67930cf9434SAndreas Gohr AND P.view_x != 0 68030cf9434SAndreas Gohr AND P.view_y != 0 681b6632b6eSAndreas Gohr GROUP BY resolution 682b6632b6eSAndreas Gohr ORDER BY cnt DESC" . 683f9e60319SAndreas Gohr $this->limit; 684b6632b6eSAndreas Gohr 685*44f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 686b6632b6eSAndreas Gohr } 687b6632b6eSAndreas Gohr 688f9e60319SAndreas Gohr /** 689f9e60319SAndreas Gohr * @return array 690f9e60319SAndreas Gohr */ 691f9e60319SAndreas Gohr public function seenusers(): array 692b6632b6eSAndreas Gohr { 69310dcb86fSAndreas Gohr $sql = "SELECT `user`, MAX(`dt`) as dt 69410dcb86fSAndreas Gohr FROM users 69510dcb86fSAndreas Gohr WHERE `user` IS NOT NULL 69610dcb86fSAndreas Gohr AND `user` != '' 69710dcb86fSAndreas Gohr GROUP BY `user` 698b6632b6eSAndreas Gohr ORDER BY `dt` DESC" . 699f9e60319SAndreas Gohr $this->limit; 700b6632b6eSAndreas Gohr 701f9e60319SAndreas Gohr return $this->db->queryAll($sql); 702b6632b6eSAndreas Gohr } 703b6632b6eSAndreas Gohr} 704