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 = ''; 1844f81330SAndreas 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'); 52*57819987SAnna Dabrowska 53*57819987SAnna Dabrowska $this->setTimezone(); 54*57819987SAnna Dabrowska } 55*57819987SAnna Dabrowska 56*57819987SAnna Dabrowska /** 57*57819987SAnna Dabrowska * Force configured timezone. 58*57819987SAnna Dabrowska * This is useful if you cannot set localtime on the server. 59*57819987SAnna Dabrowska * 60*57819987SAnna Dabrowska * @return void 61*57819987SAnna Dabrowska */ 62*57819987SAnna Dabrowska public function setTimezone() 63*57819987SAnna Dabrowska { 64*57819987SAnna Dabrowska $timezoneId = $this->hlp->getConf('timezone'); 65*57819987SAnna Dabrowska if (!$timezoneId || !in_array($timezoneId, \DateTimeZone::listIdentifiers())) return; 66*57819987SAnna Dabrowska 67*57819987SAnna Dabrowska try { 68*57819987SAnna Dabrowska $dateTime = new \DateTime($this->from, new \DateTimeZone($timezoneId)); 69*57819987SAnna Dabrowska $this->tz = $dateTime->format('P'); 70*57819987SAnna Dabrowska } catch (\Exception $e) { 71*57819987SAnna Dabrowska \dokuwiki\Logger::error($e->getMessage()); 72*57819987SAnna Dabrowska } 73f9e60319SAndreas Gohr } 74f9e60319SAndreas Gohr 75f9e60319SAndreas Gohr /** 76f9e60319SAndreas Gohr * Set the pagination settings for some queries 77f9e60319SAndreas Gohr * 78f9e60319SAndreas Gohr * @param int $start The start offset 79f9e60319SAndreas Gohr * @param int $limit The number of results. If one more is returned, there is another page 80f9e60319SAndreas Gohr * @return void 81f9e60319SAndreas Gohr */ 82f9e60319SAndreas Gohr public function setPagination(int $start, int $limit) 83f9e60319SAndreas Gohr { 84f9e60319SAndreas Gohr // when a limit is set, one more is fetched to indicate when a next page exists 85f9e60319SAndreas Gohr if ($limit) $limit += 1; 86f9e60319SAndreas Gohr 87f9e60319SAndreas Gohr if ($limit) { 88f9e60319SAndreas Gohr $this->limit = " LIMIT $start,$limit"; 89f9e60319SAndreas Gohr } elseif ($start) { 90f9e60319SAndreas Gohr $this->limit = " OFFSET $start"; 91f9e60319SAndreas Gohr } 92b6632b6eSAndreas Gohr } 93b6632b6eSAndreas Gohr 94b6632b6eSAndreas Gohr /** 95b6632b6eSAndreas Gohr * Return some aggregated statistics 96b6632b6eSAndreas Gohr */ 97f9e60319SAndreas Gohr public function aggregate(): array 98b6632b6eSAndreas Gohr { 992a30f557SAndreas Gohr // init some values that might not be set 1002a30f557SAndreas Gohr $data = [ 1012a30f557SAndreas Gohr 'referers' => 0, // total number of (external) referrers 1022a30f557SAndreas Gohr 'external' => 0, // external referrers 1032a30f557SAndreas Gohr 'search' => 0, // search engine referrers 1042a30f557SAndreas Gohr 'direct' => 0, // direct referrers 1052a30f557SAndreas Gohr 'internal' => 0, // internal referrers 1062a30f557SAndreas Gohr 'bouncerate' => 0, 1072a30f557SAndreas Gohr 'newvisitors' => 0, 1082a30f557SAndreas Gohr ]; 109b6632b6eSAndreas Gohr 11010dcb86fSAndreas Gohr // Count referrer types by joining with referers table 11110dcb86fSAndreas Gohr $sql = "SELECT 11210dcb86fSAndreas Gohr CASE 11310dcb86fSAndreas Gohr WHEN R.engine IS NOT NULL THEN 'search' 1142a30f557SAndreas Gohr WHEN R.url = '' THEN 'direct' 1152a30f557SAndreas Gohr WHEN R.url IS NOT NULL THEN 'external' 1162a30f557SAndreas Gohr ELSE 'internal' 11710dcb86fSAndreas Gohr END as ref_type, 11810dcb86fSAndreas Gohr COUNT(*) as cnt 11910dcb86fSAndreas Gohr FROM pageviews as P 12010dcb86fSAndreas Gohr LEFT JOIN referers as R ON P.ref_id = R.id 12110dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 12244f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 12330cf9434SAndreas Gohr AND S.ua_type = 'browser' 124b6632b6eSAndreas Gohr GROUP BY ref_type"; 12544f81330SAndreas Gohr $result = $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 126b6632b6eSAndreas Gohr 127f9e60319SAndreas Gohr foreach ($result as $row) { 1282a30f557SAndreas Gohr if ($row['ref_type'] == 'search') { 1292a30f557SAndreas Gohr $data['search'] = $row['cnt']; 1302a30f557SAndreas Gohr $data['referers'] += $row['cnt']; 1312a30f557SAndreas Gohr } 1322a30f557SAndreas Gohr if ($row['ref_type'] == 'direct') { 1332a30f557SAndreas Gohr $data['direct'] = $row['cnt']; 1342a30f557SAndreas Gohr $data['referers'] += $row['cnt']; 1352a30f557SAndreas Gohr } 1362a30f557SAndreas Gohr if ($row['ref_type'] == 'external') { 1372a30f557SAndreas Gohr $data['external'] = $row['cnt']; 1382a30f557SAndreas Gohr $data['referers'] += $row['cnt']; 1392a30f557SAndreas Gohr } 1402a30f557SAndreas Gohr if ($row['ref_type'] == 'internal') { 1412a30f557SAndreas Gohr $data['internal'] = $row['cnt']; 1422a30f557SAndreas Gohr } 143b6632b6eSAndreas Gohr } 144b6632b6eSAndreas Gohr 145b6632b6eSAndreas Gohr // general user and session info 14610dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT P.session) as sessions, 14710dcb86fSAndreas Gohr COUNT(P.session) as views, 14810dcb86fSAndreas Gohr COUNT(DISTINCT S.user) as users, 14944f81330SAndreas Gohr COUNT(DISTINCT S.uid) as visitors, 15044f81330SAndreas Gohr DATETIME(MAX(P.dt), ?) as last 15110dcb86fSAndreas Gohr FROM pageviews as P 15210dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 15344f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 15430cf9434SAndreas Gohr AND S.ua_type = 'browser'"; 15544f81330SAndreas Gohr $result = $this->db->queryRecord($sql, [$this->tz, $this->tz, $this->from, $this->tz, $this->to]); 156b6632b6eSAndreas Gohr 15710dcb86fSAndreas Gohr $data['users'] = $result['users']; 158f9e60319SAndreas Gohr $data['sessions'] = $result['sessions']; 159f9e60319SAndreas Gohr $data['pageviews'] = $result['views']; 160f9e60319SAndreas Gohr $data['visitors'] = $result['visitors']; 16144f81330SAndreas Gohr $data['last'] = $result['last']; 162b6632b6eSAndreas Gohr 16310dcb86fSAndreas Gohr // calculate bounce rate (sessions with only 1 page view) 164b6632b6eSAndreas Gohr if ($data['sessions']) { 165b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt 16610dcb86fSAndreas Gohr FROM ( 16710dcb86fSAndreas Gohr SELECT P.session, COUNT(*) as views 16810dcb86fSAndreas Gohr FROM pageviews as P 16910dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 17044f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 17130cf9434SAndreas Gohr AND S.ua_type = 'browser' 17210dcb86fSAndreas Gohr GROUP BY P.session 17310dcb86fSAndreas Gohr HAVING views = 1 17410dcb86fSAndreas Gohr )"; 17544f81330SAndreas Gohr $count = $this->db->queryValue($sql, [$this->tz, $this->from, $this->tz, $this->to]); 176f9e60319SAndreas Gohr $data['bouncerate'] = $count * 100 / $data['sessions']; 177f9e60319SAndreas Gohr $data['newvisitors'] = $count * 100 / $data['sessions']; 178b6632b6eSAndreas Gohr } 179b6632b6eSAndreas Gohr 180b6632b6eSAndreas Gohr // calculate avg. number of views per session 181b6632b6eSAndreas Gohr $sql = "SELECT AVG(views) as cnt 18210dcb86fSAndreas Gohr FROM ( 18310dcb86fSAndreas Gohr SELECT P.session, COUNT(*) as views 18410dcb86fSAndreas Gohr FROM pageviews as P 18510dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 18644f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 18730cf9434SAndreas Gohr AND S.ua_type = 'browser' 18810dcb86fSAndreas Gohr GROUP BY P.session 18910dcb86fSAndreas Gohr )"; 19044f81330SAndreas Gohr $data['avgpages'] = $this->db->queryValue($sql, [$this->tz, $this->from, $this->tz, $this->to]); 191b6632b6eSAndreas Gohr 192b6632b6eSAndreas Gohr // average time spent on the site 19310dcb86fSAndreas Gohr $sql = "SELECT AVG((julianday(end) - julianday(dt)) * 24 * 60) as time 19410dcb86fSAndreas Gohr FROM sessions as S 19510dcb86fSAndreas Gohr WHERE S.dt >= ? AND S.dt <= ? 19610dcb86fSAndreas Gohr AND S.dt != S.end 19744f81330SAndreas Gohr AND DATETIME(S.dt, ?) >= ? AND DATETIME(S.dt, ?) <= ? 19830cf9434SAndreas Gohr AND S.ua_type = 'browser'"; 19944f81330SAndreas Gohr $data['timespent'] = $this->db->queryValue($sql, [$this->tz, $this->from, $this->tz, $this->to]); 200b6632b6eSAndreas Gohr 201b6632b6eSAndreas Gohr // logins 202b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as logins 2037428e816SAndreas Gohr FROM logins as A 20444f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 20530cf9434SAndreas Gohr AND (type = 'l' OR type = 'p')"; 20644f81330SAndreas Gohr $data['logins'] = $this->db->queryValue($sql, [$this->tz, $this->from, $this->tz, $this->to]); 207b6632b6eSAndreas Gohr 208b6632b6eSAndreas Gohr // registrations 209b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as registrations 2107428e816SAndreas Gohr FROM logins as A 21144f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 21230cf9434SAndreas Gohr AND type = 'C'"; 21344f81330SAndreas Gohr $data['registrations'] = $this->db->queryValue($sql, [$this->tz, $this->from, $this->tz, $this->to]); 214b6632b6eSAndreas Gohr 21510dcb86fSAndreas Gohr // current users (based on recent sessions) 21610dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT uid) as current 21710dcb86fSAndreas Gohr FROM sessions 21810dcb86fSAndreas Gohr WHERE end >= datetime('now', '-10 minutes')"; 219f9e60319SAndreas Gohr $data['current'] = $this->db->queryValue($sql); 220b6632b6eSAndreas Gohr 221b6632b6eSAndreas Gohr return $data; 222b6632b6eSAndreas Gohr } 223b6632b6eSAndreas Gohr 224b6632b6eSAndreas Gohr 225b6632b6eSAndreas Gohr /** 226b6632b6eSAndreas Gohr * Return some trend data about visits and edits in the wiki 227f9e60319SAndreas Gohr * 228f9e60319SAndreas Gohr * @param bool $hours Use hour resolution rather than days 229f9e60319SAndreas Gohr * @return array 230b6632b6eSAndreas Gohr */ 231f9e60319SAndreas Gohr public function dashboardviews(bool $hours = false): array 232b6632b6eSAndreas Gohr { 233b6632b6eSAndreas Gohr if ($hours) { 23444f81330SAndreas Gohr $TIME = "strftime('%H', DATETIME(P.dt, '$this->tz'))"; 235b6632b6eSAndreas Gohr } else { 23644f81330SAndreas Gohr $TIME = "DATE(DATETIME(P.dt, '$this->tz'))"; 237b6632b6eSAndreas Gohr } 238b6632b6eSAndreas Gohr 239b6632b6eSAndreas Gohr $data = []; 240b6632b6eSAndreas Gohr 241b6632b6eSAndreas Gohr // access trends 242b6632b6eSAndreas Gohr $sql = "SELECT $TIME as time, 24310dcb86fSAndreas Gohr COUNT(DISTINCT P.session) as sessions, 24410dcb86fSAndreas Gohr COUNT(P.session) as pageviews, 24510dcb86fSAndreas Gohr COUNT(DISTINCT S.uid) as visitors 24610dcb86fSAndreas Gohr FROM pageviews as P 24710dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 24844f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 24930cf9434SAndreas Gohr AND S.ua_type = 'browser' 250b6632b6eSAndreas Gohr GROUP BY $TIME 251b6632b6eSAndreas Gohr ORDER BY time"; 25244f81330SAndreas Gohr $result = $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 253b6632b6eSAndreas Gohr foreach ($result as $row) { 254b6632b6eSAndreas Gohr $data[$row['time']]['sessions'] = $row['sessions']; 255b6632b6eSAndreas Gohr $data[$row['time']]['pageviews'] = $row['pageviews']; 256b6632b6eSAndreas Gohr $data[$row['time']]['visitors'] = $row['visitors']; 257b6632b6eSAndreas Gohr } 258b6632b6eSAndreas Gohr return $data; 259b6632b6eSAndreas Gohr } 260b6632b6eSAndreas Gohr 261f9e60319SAndreas Gohr /** 262f9e60319SAndreas Gohr * @param bool $hours Use hour resolution rather than days 263f9e60319SAndreas Gohr * @return array 264f9e60319SAndreas Gohr */ 265f9e60319SAndreas Gohr public function dashboardwiki(bool $hours = false): array 266b6632b6eSAndreas Gohr { 267b6632b6eSAndreas Gohr if ($hours) { 26844f81330SAndreas Gohr $TIME = "strftime('%H', DATETIME(dt, '$this->tz'))"; 269b6632b6eSAndreas Gohr } else { 27044f81330SAndreas Gohr $TIME = "DATE(DATETIME(dt, '$this->tz'))"; 271b6632b6eSAndreas Gohr } 272b6632b6eSAndreas Gohr 273b6632b6eSAndreas Gohr $data = []; 274b6632b6eSAndreas Gohr 275b6632b6eSAndreas Gohr // edit trends 276b6632b6eSAndreas Gohr foreach (['E', 'C', 'D'] as $type) { 277b6632b6eSAndreas Gohr $sql = "SELECT $TIME as time, 278b6632b6eSAndreas Gohr COUNT(*) as cnt 2797428e816SAndreas Gohr FROM edits as A 28044f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 28130cf9434SAndreas Gohr AND type = '$type' 282b6632b6eSAndreas Gohr GROUP BY $TIME 283b6632b6eSAndreas Gohr ORDER BY time"; 28444f81330SAndreas Gohr $result = $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 285b6632b6eSAndreas Gohr foreach ($result as $row) { 286b6632b6eSAndreas Gohr $data[$row['time']][$type] = $row['cnt']; 287b6632b6eSAndreas Gohr } 288b6632b6eSAndreas Gohr } 289b6632b6eSAndreas Gohr ksort($data); 290b6632b6eSAndreas Gohr return $data; 291b6632b6eSAndreas Gohr } 292b6632b6eSAndreas Gohr 293f9e60319SAndreas Gohr /** 294f9e60319SAndreas Gohr * @param string $info Which type of history to select (FIXME which ones are there?) 295f9e60319SAndreas Gohr * @param string $interval Group data by this interval (days, weeks, months) 296f9e60319SAndreas Gohr * @return array 297f9e60319SAndreas Gohr */ 298f9e60319SAndreas Gohr public function history(string $info, string $interval = 'day'): array 299b6632b6eSAndreas Gohr { 300b6632b6eSAndreas Gohr if ($interval == 'weeks') { 30144f81330SAndreas Gohr $TIME = "strftime('%Y', DATETIME(dt, '$this->tz')), strftime('%W', DATETIME(dt, '$this->tz'))"; 302b6632b6eSAndreas Gohr } elseif ($interval == 'months') { 30344f81330SAndreas Gohr $TIME = "strftime('%Y-%m', DATETIME(dt, '$this->tz'))"; 304b6632b6eSAndreas Gohr } else { 30544f81330SAndreas Gohr $TIME = "strftime('%d-%m', DATETIME(dt, '$this->tz'))"; 306b6632b6eSAndreas Gohr } 307b6632b6eSAndreas Gohr 308b6632b6eSAndreas Gohr $mod = 1; 309b6632b6eSAndreas Gohr if ($info == 'media_size' || $info == 'page_size') { 310b6632b6eSAndreas Gohr $mod = 1024 * 1024; 311b6632b6eSAndreas Gohr } 312b6632b6eSAndreas Gohr 313b6632b6eSAndreas Gohr $sql = "SELECT $TIME as time, 3147428e816SAndreas Gohr AVG(value)/$mod as cnt 3157428e816SAndreas Gohr FROM history as A 31644f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 3177428e816SAndreas Gohr AND info = ? 318b6632b6eSAndreas Gohr GROUP BY $TIME 319b6632b6eSAndreas Gohr ORDER BY $TIME"; 32044f81330SAndreas Gohr 32144f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to, $info]); 322b6632b6eSAndreas Gohr } 323b6632b6eSAndreas Gohr 324f9e60319SAndreas Gohr /** 325f9e60319SAndreas Gohr * @return array 326f9e60319SAndreas Gohr */ 327f9e60319SAndreas Gohr public function searchengines(): array 328b6632b6eSAndreas Gohr { 32910dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, R.engine 3306f2bdce1SAndreas Gohr FROM pageviews as P, 3316f2bdce1SAndreas Gohr referers as R 33244f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 3336f2bdce1SAndreas Gohr AND P.ref_id = R.id 33410dcb86fSAndreas Gohr AND R.engine != '' 33510dcb86fSAndreas Gohr GROUP BY R.engine 33610dcb86fSAndreas Gohr ORDER BY cnt DESC, R.engine" . 337f9e60319SAndreas Gohr $this->limit; 33844f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 339b6632b6eSAndreas Gohr } 340b6632b6eSAndreas Gohr 341f9e60319SAndreas Gohr /** 342f9e60319SAndreas Gohr * @return array 343f9e60319SAndreas Gohr */ 3442a30f557SAndreas Gohr public function searchphrases(): array 345b6632b6eSAndreas Gohr { 3462a30f557SAndreas Gohr $sql = "SELECT COUNT(*) as cnt, query, query as ilookup 3472a30f557SAndreas Gohr FROM search 34844f81330SAndreas Gohr WHERE DATETIME(dt, ?) >= ? AND DATETIME(dt, ?) <= ? 3492a30f557SAndreas Gohr GROUP BY query 3502a30f557SAndreas Gohr ORDER BY cnt DESC, query" . 351f9e60319SAndreas Gohr $this->limit; 35244f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 353b6632b6eSAndreas Gohr } 354b6632b6eSAndreas Gohr 355f9e60319SAndreas Gohr /** 356f9e60319SAndreas Gohr * @return array 357f9e60319SAndreas Gohr */ 3582a30f557SAndreas Gohr public function searchwords(): array 359b6632b6eSAndreas Gohr { 3602a30f557SAndreas Gohr $sql = "SELECT COUNT(*) as cnt, SW.word, SW.word as ilookup 3612a30f557SAndreas Gohr FROM search as S, 3622a30f557SAndreas Gohr searchwords as SW 36344f81330SAndreas Gohr WHERE DATETIME(S.dt, ?) >= ? AND DATETIME(S.dt, ?) <= ? 3642a30f557SAndreas Gohr AND S.id = SW.sid 36510dcb86fSAndreas Gohr GROUP BY SW.word 36610dcb86fSAndreas Gohr ORDER BY cnt DESC, SW.word" . 367f9e60319SAndreas Gohr $this->limit; 36844f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 369b6632b6eSAndreas Gohr } 370b6632b6eSAndreas Gohr 371f9e60319SAndreas Gohr /** 372f9e60319SAndreas Gohr * @return array 373f9e60319SAndreas Gohr */ 374f9e60319SAndreas Gohr public function outlinks(): array 375b6632b6eSAndreas Gohr { 376b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, link as url 3777428e816SAndreas Gohr FROM outlinks as A 37844f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 379b6632b6eSAndreas Gohr GROUP BY link 380b6632b6eSAndreas Gohr ORDER BY cnt DESC, link" . 381f9e60319SAndreas Gohr $this->limit; 38244f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 383b6632b6eSAndreas Gohr } 384b6632b6eSAndreas Gohr 385f9e60319SAndreas Gohr /** 386f9e60319SAndreas Gohr * @return array 387f9e60319SAndreas Gohr */ 388f9e60319SAndreas Gohr public function pages(): array 389b6632b6eSAndreas Gohr { 39010dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, P.page 3916f2bdce1SAndreas Gohr FROM pageviews as P, 3926f2bdce1SAndreas Gohr sessions as S 39344f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 3946f2bdce1SAndreas Gohr AND P.session = S.session 39530cf9434SAndreas Gohr AND S.ua_type = 'browser' 39610dcb86fSAndreas Gohr GROUP BY P.page 39710dcb86fSAndreas Gohr ORDER BY cnt DESC, P.page" . 398f9e60319SAndreas Gohr $this->limit; 39944f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 400b6632b6eSAndreas Gohr } 401b6632b6eSAndreas Gohr 402f9e60319SAndreas Gohr /** 403f9e60319SAndreas Gohr * @return array 404f9e60319SAndreas Gohr */ 405f9e60319SAndreas Gohr public function edits(): array 406b6632b6eSAndreas Gohr { 407b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, page 4087428e816SAndreas Gohr FROM edits as A 40944f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 410b6632b6eSAndreas Gohr GROUP BY page 411b6632b6eSAndreas Gohr ORDER BY cnt DESC, page" . 412f9e60319SAndreas Gohr $this->limit; 41344f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 414b6632b6eSAndreas Gohr } 415b6632b6eSAndreas Gohr 416f9e60319SAndreas Gohr /** 417f9e60319SAndreas Gohr * @return array 418f9e60319SAndreas Gohr */ 419f9e60319SAndreas Gohr public function images(): array 420b6632b6eSAndreas Gohr { 421b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, media, SUM(size) as filesize 4227428e816SAndreas Gohr FROM media as A 42344f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 42430cf9434SAndreas Gohr AND mime1 = 'image' 425b6632b6eSAndreas Gohr GROUP BY media 426b6632b6eSAndreas Gohr ORDER BY cnt DESC, media" . 427f9e60319SAndreas Gohr $this->limit; 42844f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 429b6632b6eSAndreas Gohr } 430b6632b6eSAndreas Gohr 431f9e60319SAndreas Gohr /** 432f9e60319SAndreas Gohr * @return array 433f9e60319SAndreas Gohr */ 434f9e60319SAndreas Gohr public function imagessum(): array 435b6632b6eSAndreas Gohr { 436b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, SUM(size) as filesize 4377428e816SAndreas Gohr FROM media as A 43844f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 43930cf9434SAndreas Gohr AND mime1 = 'image'"; 44044f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 441b6632b6eSAndreas Gohr } 442b6632b6eSAndreas Gohr 443f9e60319SAndreas Gohr /** 444f9e60319SAndreas Gohr * @return array 445f9e60319SAndreas Gohr */ 446f9e60319SAndreas Gohr public function downloads(): array 447b6632b6eSAndreas Gohr { 448b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, media, SUM(size) as filesize 4497428e816SAndreas Gohr FROM media as A 45044f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 45130cf9434SAndreas Gohr AND mime1 != 'image' 452b6632b6eSAndreas Gohr GROUP BY media 453b6632b6eSAndreas Gohr ORDER BY cnt DESC, media" . 454f9e60319SAndreas Gohr $this->limit; 45544f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 456b6632b6eSAndreas Gohr } 457b6632b6eSAndreas Gohr 458f9e60319SAndreas Gohr /** 459f9e60319SAndreas Gohr * @return array 460f9e60319SAndreas Gohr */ 461f9e60319SAndreas Gohr public function downloadssum(): array 462b6632b6eSAndreas Gohr { 463b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, SUM(size) as filesize 4647428e816SAndreas Gohr FROM media as A 46544f81330SAndreas Gohr WHERE DATETIME(A.dt, ?) >= ? AND DATETIME(A.dt, ?) <= ? 46630cf9434SAndreas Gohr AND mime1 != 'image'"; 46744f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 468b6632b6eSAndreas Gohr } 469b6632b6eSAndreas Gohr 470f9e60319SAndreas Gohr /** 471f9e60319SAndreas Gohr * @return array 472f9e60319SAndreas Gohr */ 473f9e60319SAndreas Gohr public function referer(): array 474b6632b6eSAndreas Gohr { 47510dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, R.url 47610dcb86fSAndreas Gohr FROM pageviews as P 47710dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 47810dcb86fSAndreas Gohr LEFT JOIN referers as R ON P.ref_id = R.id 47944f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 48030cf9434SAndreas Gohr AND S.ua_type = 'browser' 48110dcb86fSAndreas Gohr AND R.url IS NOT NULL 48210dcb86fSAndreas Gohr AND R.url != '' 48310dcb86fSAndreas Gohr AND R.engine IS NULL 48410dcb86fSAndreas Gohr GROUP BY R.url 48510dcb86fSAndreas Gohr ORDER BY cnt DESC, R.url" . 486f9e60319SAndreas Gohr $this->limit; 48744f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 488b6632b6eSAndreas Gohr } 489b6632b6eSAndreas Gohr 490f9e60319SAndreas Gohr /** 491f9e60319SAndreas Gohr * @return array 492f9e60319SAndreas Gohr */ 493f9e60319SAndreas Gohr public function newreferer(): array 494b6632b6eSAndreas Gohr { 49510dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, R.url 49610dcb86fSAndreas Gohr FROM pageviews as P 49710dcb86fSAndreas Gohr LEFT JOIN sessions as S ON P.session = S.session 49810dcb86fSAndreas Gohr LEFT JOIN referers as R ON P.ref_id = R.id 49944f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 50030cf9434SAndreas Gohr AND S.ua_type = 'browser' 50110dcb86fSAndreas Gohr AND R.url IS NOT NULL 50210dcb86fSAndreas Gohr AND R.url != '' 50310dcb86fSAndreas Gohr AND R.engine IS NULL 50444f81330SAndreas Gohr AND DATETIME(R.dt, ?) >= ? 50510dcb86fSAndreas Gohr GROUP BY R.url 50610dcb86fSAndreas Gohr ORDER BY cnt DESC, R.url" . 507f9e60319SAndreas Gohr $this->limit; 50844f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to, $this->tz, $this->from]); 509b6632b6eSAndreas Gohr } 510b6632b6eSAndreas Gohr 511f9e60319SAndreas Gohr /** 512f9e60319SAndreas Gohr * @return array 513f9e60319SAndreas Gohr */ 514f9e60319SAndreas Gohr public function countries(): array 515b6632b6eSAndreas Gohr { 51610dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT P.session) as cnt, I.country 5176f2bdce1SAndreas Gohr FROM pageviews as P, 5186f2bdce1SAndreas Gohr iplocation as I 51944f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 5206f2bdce1SAndreas Gohr AND P.ip = I.ip 52110dcb86fSAndreas Gohr AND I.country != '' 52210dcb86fSAndreas Gohr GROUP BY I.code 52310dcb86fSAndreas Gohr ORDER BY cnt DESC, I.country" . 524f9e60319SAndreas Gohr $this->limit; 52544f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 526b6632b6eSAndreas Gohr } 527b6632b6eSAndreas Gohr 528f9e60319SAndreas Gohr /** 529f9e60319SAndreas Gohr * @param bool $ext return extended information 530f9e60319SAndreas Gohr * @return array 531f9e60319SAndreas Gohr */ 5322a30f557SAndreas Gohr public function browsers(bool $ext = false): array 533b6632b6eSAndreas Gohr { 534b6632b6eSAndreas Gohr if ($ext) { 53510dcb86fSAndreas Gohr $sel = 'S.ua_info as browser, S.ua_ver'; 53610dcb86fSAndreas Gohr $grp = 'S.ua_info, S.ua_ver'; 537b6632b6eSAndreas Gohr } else { 5382a30f557SAndreas Gohr $sel = 'S.ua_info as browser'; 53910dcb86fSAndreas Gohr $grp = 'S.ua_info'; 540b6632b6eSAndreas Gohr } 541b6632b6eSAndreas Gohr 54210dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.session) as cnt, $sel 54310dcb86fSAndreas Gohr FROM sessions as S 54444f81330SAndreas Gohr WHERE DATETIME(S.dt, ?) >= ? AND DATETIME(S.dt, ?) <= ? 54530cf9434SAndreas Gohr AND S.ua_type = 'browser' 546b6632b6eSAndreas Gohr GROUP BY $grp 54710dcb86fSAndreas Gohr ORDER BY cnt DESC, S.ua_info" . 548f9e60319SAndreas Gohr $this->limit; 54944f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 550b6632b6eSAndreas Gohr } 551b6632b6eSAndreas Gohr 552f9e60319SAndreas Gohr /** 553f9e60319SAndreas Gohr * @return array 554f9e60319SAndreas Gohr */ 555f9e60319SAndreas Gohr public function os(): array 556b6632b6eSAndreas Gohr { 55710dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.session) as cnt, S.os 55810dcb86fSAndreas Gohr FROM sessions as S 55944f81330SAndreas Gohr WHERE DATETIME(S.dt, ?) >= ? AND DATETIME(S.dt, ?) <= ? 56030cf9434SAndreas Gohr AND S.ua_type = 'browser' 56110dcb86fSAndreas Gohr GROUP BY S.os 56210dcb86fSAndreas Gohr ORDER BY cnt DESC, S.os" . 563f9e60319SAndreas Gohr $this->limit; 56444f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 565b6632b6eSAndreas Gohr } 566b6632b6eSAndreas Gohr 567f9e60319SAndreas Gohr /** 568f9e60319SAndreas Gohr * @return array 569f9e60319SAndreas Gohr */ 5709fdd7e51SAndreas Gohr public function topdomain(): array 5719fdd7e51SAndreas Gohr { 5729fdd7e51SAndreas Gohr $sql = "SELECT COUNT(*) as cnt, U.domain 5739fdd7e51SAndreas Gohr FROM pageviews as P, 5749fdd7e51SAndreas Gohr sessions as S, 5759fdd7e51SAndreas Gohr users as U 57644f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 5779fdd7e51SAndreas Gohr AND P.session = S.session 5789fdd7e51SAndreas Gohr AND S.user = U.user 57930cf9434SAndreas Gohr AND S.ua_type = 'browser' 5809fdd7e51SAndreas Gohr AND S.user IS NOT NULL 5819fdd7e51SAndreas Gohr GROUP BY U.domain 5829fdd7e51SAndreas Gohr ORDER BY cnt DESC, U.domain" . 5839fdd7e51SAndreas Gohr $this->limit; 58444f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 5859fdd7e51SAndreas Gohr } 5869fdd7e51SAndreas Gohr 5879fdd7e51SAndreas Gohr /** 5889fdd7e51SAndreas Gohr * @return array 5899fdd7e51SAndreas Gohr */ 590f9e60319SAndreas Gohr public function topuser(): array 591b6632b6eSAndreas Gohr { 59210dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, S.user 5936f2bdce1SAndreas Gohr FROM pageviews as P, 5946f2bdce1SAndreas Gohr sessions as S 59544f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 5966f2bdce1SAndreas Gohr AND P.session = S.session 59730cf9434SAndreas Gohr AND S.ua_type = 'browser' 598b7091bfdSAndreas Gohr AND S.user IS NOT NULL 59910dcb86fSAndreas Gohr GROUP BY S.user 60010dcb86fSAndreas Gohr ORDER BY cnt DESC, S.user" . 601f9e60319SAndreas Gohr $this->limit; 60244f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 603b6632b6eSAndreas Gohr } 604b6632b6eSAndreas Gohr 605f9e60319SAndreas Gohr /** 606f9e60319SAndreas Gohr * @return array 607f9e60319SAndreas Gohr */ 608f9e60319SAndreas Gohr public function topeditor(): array 609b6632b6eSAndreas Gohr { 610b6632b6eSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, user 6116f2bdce1SAndreas Gohr FROM edits as E, 6126f2bdce1SAndreas Gohr sessions as S 61344f81330SAndreas Gohr WHERE DATETIME(E.dt, ?) >= ? AND DATETIME(E.dt, ?) <= ? 6146f2bdce1SAndreas Gohr AND E.session = S.session 615b7091bfdSAndreas Gohr AND S.user IS NOT NULL 616b6632b6eSAndreas Gohr GROUP BY user 617b6632b6eSAndreas Gohr ORDER BY cnt DESC, user" . 618f9e60319SAndreas Gohr $this->limit; 61944f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 620b6632b6eSAndreas Gohr } 621b6632b6eSAndreas Gohr 622f9e60319SAndreas Gohr /** 623f9e60319SAndreas Gohr * @return array 624f9e60319SAndreas Gohr */ 625f9e60319SAndreas Gohr public function topgroup(): array 626b6632b6eSAndreas Gohr { 62710dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, G.`group` 6286f2bdce1SAndreas Gohr FROM pageviews as P, 6296f2bdce1SAndreas Gohr sessions as S, 6306f2bdce1SAndreas Gohr groups as G 63144f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 6326f2bdce1SAndreas Gohr AND P.session = S.session 6336f2bdce1SAndreas Gohr AND S.user = G.user 63430cf9434SAndreas Gohr AND S.ua_type = 'browser' 63510dcb86fSAndreas Gohr GROUP BY G.`group` 63610dcb86fSAndreas Gohr ORDER BY cnt DESC, G.`group`" . 637f9e60319SAndreas Gohr $this->limit; 63844f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 639b6632b6eSAndreas Gohr } 640b6632b6eSAndreas Gohr 641f9e60319SAndreas Gohr /** 642f9e60319SAndreas Gohr * @return array 643f9e60319SAndreas Gohr */ 644f9e60319SAndreas Gohr public function topgroupedit(): array 645b6632b6eSAndreas Gohr { 64610dcb86fSAndreas Gohr $sql = "SELECT COUNT(*) as cnt, G.`group` 6476f2bdce1SAndreas Gohr FROM edits as E, 6486f2bdce1SAndreas Gohr sessions as S, 6496f2bdce1SAndreas Gohr groups as G 65044f81330SAndreas Gohr WHERE DATETIME(E.dt, ?) >= ? AND DATETIME(E.dt, ?) <= ? 6516f2bdce1SAndreas Gohr AND E.session = S.session 6526f2bdce1SAndreas Gohr AND S.user = G.user 65310dcb86fSAndreas Gohr GROUP BY G.`group` 65410dcb86fSAndreas Gohr ORDER BY cnt DESC, G.`group`" . 655f9e60319SAndreas Gohr $this->limit; 65644f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 657b6632b6eSAndreas Gohr } 658b6632b6eSAndreas Gohr 659b6632b6eSAndreas Gohr 660f9e60319SAndreas Gohr /** 661f9e60319SAndreas Gohr * @return array 662f9e60319SAndreas Gohr */ 663f9e60319SAndreas Gohr public function resolution(): array 664b6632b6eSAndreas Gohr { 66510dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.uid) as cnt, 66610dcb86fSAndreas Gohr ROUND(P.screen_x/100)*100 as res_x, 66710dcb86fSAndreas Gohr ROUND(P.screen_y/100)*100 as res_y, 668bd514593SAndreas Gohr CAST(ROUND(P.screen_x/100)*100 AS int) 669bd514593SAndreas Gohr || 'x' || 670bd514593SAndreas Gohr CAST(ROUND(P.screen_y/100)*100 AS int) as resolution 6716f2bdce1SAndreas Gohr FROM pageviews as P, 6726f2bdce1SAndreas Gohr sessions as S 67344f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 6746f2bdce1SAndreas Gohr AND P.session = S.session 67530cf9434SAndreas Gohr AND S.ua_type = 'browser' 67630cf9434SAndreas Gohr AND P.screen_x != 0 67730cf9434SAndreas Gohr AND P.screen_y != 0 678b6632b6eSAndreas Gohr GROUP BY resolution 679b6632b6eSAndreas Gohr ORDER BY cnt DESC" . 680f9e60319SAndreas Gohr $this->limit; 68144f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 682b6632b6eSAndreas Gohr } 683b6632b6eSAndreas Gohr 684f9e60319SAndreas Gohr /** 685f9e60319SAndreas Gohr * @return array 686f9e60319SAndreas Gohr */ 687f9e60319SAndreas Gohr public function viewport(): array 688b6632b6eSAndreas Gohr { 68910dcb86fSAndreas Gohr $sql = "SELECT COUNT(DISTINCT S.uid) as cnt, 69010dcb86fSAndreas Gohr ROUND(P.view_x/100)*100 as res_x, 69110dcb86fSAndreas Gohr ROUND(P.view_y/100)*100 as res_y, 692bd514593SAndreas Gohr CAST(ROUND(P.view_x/100)*100 AS int) 693bd514593SAndreas Gohr || 'x' || 694bd514593SAndreas Gohr CAST(ROUND(P.view_y/100)*100 AS int) as resolution 6956f2bdce1SAndreas Gohr FROM pageviews as P, 6966f2bdce1SAndreas Gohr sessions as S 69744f81330SAndreas Gohr WHERE DATETIME(P.dt, ?) >= ? AND DATETIME(P.dt, ?) <= ? 6986f2bdce1SAndreas Gohr AND P.session = S.session 69930cf9434SAndreas Gohr AND S.ua_type = 'browser' 70030cf9434SAndreas Gohr AND P.view_x != 0 70130cf9434SAndreas Gohr AND P.view_y != 0 702b6632b6eSAndreas Gohr GROUP BY resolution 703b6632b6eSAndreas Gohr ORDER BY cnt DESC" . 704f9e60319SAndreas Gohr $this->limit; 705b6632b6eSAndreas Gohr 70644f81330SAndreas Gohr return $this->db->queryAll($sql, [$this->tz, $this->from, $this->tz, $this->to]); 707b6632b6eSAndreas Gohr } 708b6632b6eSAndreas Gohr 709f9e60319SAndreas Gohr /** 710f9e60319SAndreas Gohr * @return array 711f9e60319SAndreas Gohr */ 712f9e60319SAndreas Gohr public function seenusers(): array 713b6632b6eSAndreas Gohr { 71410dcb86fSAndreas Gohr $sql = "SELECT `user`, MAX(`dt`) as dt 71510dcb86fSAndreas Gohr FROM users 71610dcb86fSAndreas Gohr WHERE `user` IS NOT NULL 71710dcb86fSAndreas Gohr AND `user` != '' 71810dcb86fSAndreas Gohr GROUP BY `user` 719b6632b6eSAndreas Gohr ORDER BY `dt` DESC" . 720f9e60319SAndreas Gohr $this->limit; 721b6632b6eSAndreas Gohr 722f9e60319SAndreas Gohr return $this->db->queryAll($sql); 723b6632b6eSAndreas Gohr } 724b6632b6eSAndreas Gohr} 725