| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 4 | //
 | 
        
           |  |  | 5 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 6 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 7 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 8 | // (at your option) any later version.
 | 
        
           |  |  | 9 | //
 | 
        
           |  |  | 10 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 13 | // GNU General Public License for more details.
 | 
        
           |  |  | 14 | //
 | 
        
           |  |  | 15 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 16 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 17 |   | 
        
           |  |  | 18 | /**
 | 
        
           |  |  | 19 |  * @package    core
 | 
        
           |  |  | 20 |  * @subpackage stats
 | 
        
           |  |  | 21 |  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
 | 
        
           |  |  | 22 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 23 |  */
 | 
        
           |  |  | 24 |   | 
        
           |  |  | 25 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 26 |   | 
        
           |  |  | 27 | /** THESE CONSTANTS ARE USED FOR THE REPORTING PAGE. */
 | 
        
           |  |  | 28 |   | 
        
           |  |  | 29 | define('STATS_REPORT_LOGINS',1); // double impose logins and unique logins on a line graph. site course only.
 | 
        
           |  |  | 30 | define('STATS_REPORT_READS',2); // double impose student reads and teacher reads on a line graph.
 | 
        
           |  |  | 31 | define('STATS_REPORT_WRITES',3); // double impose student writes and teacher writes on a line graph.
 | 
        
           |  |  | 32 | define('STATS_REPORT_ACTIVITY',4); // 2+3 added up, teacher vs student.
 | 
        
           |  |  | 33 | define('STATS_REPORT_ACTIVITYBYROLE',5); // all activity, reads vs writes, selected by role.
 | 
        
           |  |  | 34 |   | 
        
           |  |  | 35 | // user level stats reports.
 | 
        
           |  |  | 36 | define('STATS_REPORT_USER_ACTIVITY',7);
 | 
        
           |  |  | 37 | define('STATS_REPORT_USER_ALLACTIVITY',8);
 | 
        
           |  |  | 38 | define('STATS_REPORT_USER_LOGINS',9);
 | 
        
           |  |  | 39 | define('STATS_REPORT_USER_VIEW',10);  // this is the report you see on the user profile.
 | 
        
           |  |  | 40 |   | 
        
           |  |  | 41 | // admin only ranking stats reports
 | 
        
           |  |  | 42 | define('STATS_REPORT_ACTIVE_COURSES',11);
 | 
        
           |  |  | 43 | define('STATS_REPORT_ACTIVE_COURSES_WEIGHTED',12);
 | 
        
           |  |  | 44 | define('STATS_REPORT_PARTICIPATORY_COURSES',13);
 | 
        
           |  |  | 45 | define('STATS_REPORT_PARTICIPATORY_COURSES_RW',14);
 | 
        
           |  |  | 46 |   | 
        
           |  |  | 47 | // start after 0 = show dailies.
 | 
        
           |  |  | 48 | define('STATS_TIME_LASTWEEK',1);
 | 
        
           |  |  | 49 | define('STATS_TIME_LAST2WEEKS',2);
 | 
        
           |  |  | 50 | define('STATS_TIME_LAST3WEEKS',3);
 | 
        
           |  |  | 51 | define('STATS_TIME_LAST4WEEKS',4);
 | 
        
           |  |  | 52 |   | 
        
           |  |  | 53 | // start after 10 = show weeklies
 | 
        
           |  |  | 54 | define('STATS_TIME_LAST2MONTHS',12);
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 | define('STATS_TIME_LAST3MONTHS',13);
 | 
        
           |  |  | 57 | define('STATS_TIME_LAST4MONTHS',14);
 | 
        
           |  |  | 58 | define('STATS_TIME_LAST5MONTHS',15);
 | 
        
           |  |  | 59 | define('STATS_TIME_LAST6MONTHS',16);
 | 
        
           |  |  | 60 |   | 
        
           |  |  | 61 | // start after 20 = show monthlies
 | 
        
           |  |  | 62 | define('STATS_TIME_LAST7MONTHS',27);
 | 
        
           |  |  | 63 | define('STATS_TIME_LAST8MONTHS',28);
 | 
        
           |  |  | 64 | define('STATS_TIME_LAST9MONTHS',29);
 | 
        
           |  |  | 65 | define('STATS_TIME_LAST10MONTHS',30);
 | 
        
           |  |  | 66 | define('STATS_TIME_LAST11MONTHS',31);
 | 
        
           |  |  | 67 | define('STATS_TIME_LASTYEAR',32);
 | 
        
           |  |  | 68 |   | 
        
           |  |  | 69 | // different modes for what reports to offer
 | 
        
           |  |  | 70 | define('STATS_MODE_GENERAL',1);
 | 
        
           |  |  | 71 | define('STATS_MODE_DETAILED',2);
 | 
        
           |  |  | 72 | define('STATS_MODE_RANKED',3); // admins only - ranks courses
 | 
        
           |  |  | 73 |   | 
        
           |  |  | 74 | // Output string when nodebug is on
 | 
        
           |  |  | 75 | define('STATS_PLACEHOLDER_OUTPUT', '.');
 | 
        
           |  |  | 76 |   | 
        
           |  |  | 77 | /**
 | 
        
           |  |  | 78 |  * Print daily cron progress
 | 
        
           |  |  | 79 |  * @param string $ident
 | 
        
           |  |  | 80 |  */
 | 
        
           |  |  | 81 | function stats_progress($ident) {
 | 
        
           |  |  | 82 |     static $start = 0;
 | 
        
           |  |  | 83 |     static $init  = 0;
 | 
        
           |  |  | 84 |   | 
        
           |  |  | 85 |     if ($ident == 'init') {
 | 
        
           |  |  | 86 |         $init = $start = microtime(true);
 | 
        
           |  |  | 87 |         return;
 | 
        
           |  |  | 88 |     }
 | 
        
           |  |  | 89 |   | 
        
           |  |  | 90 |     $elapsed = round(microtime(true) - $start);
 | 
        
           |  |  | 91 |     $start   = microtime(true);
 | 
        
           |  |  | 92 |   | 
        
           |  |  | 93 |     if (debugging('', DEBUG_ALL)) {
 | 
        
           |  |  | 94 |         mtrace("$ident:$elapsed ", '');
 | 
        
           |  |  | 95 |     } else {
 | 
        
           |  |  | 96 |         mtrace(STATS_PLACEHOLDER_OUTPUT, '');
 | 
        
           |  |  | 97 |     }
 | 
        
           |  |  | 98 | }
 | 
        
           |  |  | 99 |   | 
        
           |  |  | 100 | /**
 | 
        
           |  |  | 101 |  * Execute individual daily statistics queries
 | 
        
           |  |  | 102 |  *
 | 
        
           |  |  | 103 |  * @param string $sql The query to run
 | 
        
           |  |  | 104 |  * @return boolean success
 | 
        
           |  |  | 105 |  */
 | 
        
           |  |  | 106 | function stats_run_query($sql, $parameters = array()) {
 | 
        
           |  |  | 107 |     global $DB;
 | 
        
           |  |  | 108 |   | 
        
           |  |  | 109 |     try {
 | 
        
           |  |  | 110 |         $DB->execute($sql, $parameters);
 | 
        
           |  |  | 111 |     } catch (dml_exception $e) {
 | 
        
           |  |  | 112 |   | 
        
           |  |  | 113 |        if (debugging('', DEBUG_ALL)) {
 | 
        
           |  |  | 114 |            mtrace($e->getMessage());
 | 
        
           |  |  | 115 |        }
 | 
        
           |  |  | 116 |        return false;
 | 
        
           |  |  | 117 |     }
 | 
        
           |  |  | 118 |     return true;
 | 
        
           |  |  | 119 | }
 | 
        
           |  |  | 120 |   | 
        
           |  |  | 121 | /**
 | 
        
           |  |  | 122 |  * Execute daily statistics gathering
 | 
        
           |  |  | 123 |  *
 | 
        
           |  |  | 124 |  * @param int $maxdays maximum number of days to be processed
 | 
        
           |  |  | 125 |  * @return boolean success
 | 
        
           |  |  | 126 |  */
 | 
        
           |  |  | 127 | function stats_cron_daily($maxdays=1) {
 | 
        
           |  |  | 128 |     global $CFG, $DB;
 | 
        
           |  |  | 129 |     require_once($CFG->libdir.'/adminlib.php');
 | 
        
           |  |  | 130 |   | 
        
           |  |  | 131 |     $now = time();
 | 
        
           |  |  | 132 |   | 
        
           |  |  | 133 |     $fpcontext = context_course::instance(SITEID, MUST_EXIST);
 | 
        
           |  |  | 134 |   | 
        
           |  |  | 135 |     // read last execution date from db
 | 
        
           |  |  | 136 |     if (!$timestart = get_config(NULL, 'statslastdaily')) {
 | 
        
           |  |  | 137 |         $timestart = stats_get_base_daily(stats_get_start_from('daily'));
 | 
        
           |  |  | 138 |         set_config('statslastdaily', $timestart);
 | 
        
           |  |  | 139 |     }
 | 
        
           |  |  | 140 |   | 
        
           |  |  | 141 |     $nextmidnight = stats_get_next_day_start($timestart);
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 |     // are there any days that need to be processed?
 | 
        
           |  |  | 144 |     if ($now < $nextmidnight) {
 | 
        
           |  |  | 145 |         return true; // everything ok and up-to-date
 | 
        
           |  |  | 146 |     }
 | 
        
           |  |  | 147 |   | 
        
           |  |  | 148 |     $timeout = empty($CFG->statsmaxruntime) ? 60*60*24 : $CFG->statsmaxruntime;
 | 
        
           |  |  | 149 |   | 
        
           |  |  | 150 |     if (!set_cron_lock('statsrunning', $now + $timeout)) {
 | 
        
           |  |  | 151 |         return false;
 | 
        
           |  |  | 152 |     }
 | 
        
           |  |  | 153 |   | 
        
           |  |  | 154 |     // first delete entries that should not be there yet
 | 
        
           |  |  | 155 |     $DB->delete_records_select('stats_daily',      "timeend > $timestart");
 | 
        
           |  |  | 156 |     $DB->delete_records_select('stats_user_daily', "timeend > $timestart");
 | 
        
           |  |  | 157 |   | 
        
           |  |  | 158 |     // Read in a few things we'll use later
 | 
        
           |  |  | 159 |     $viewactions = stats_get_action_names('view');
 | 
        
           |  |  | 160 |     $postactions = stats_get_action_names('post');
 | 
        
           |  |  | 161 |   | 
        
           |  |  | 162 |     $guest           = (int)$CFG->siteguest;
 | 
        
           |  |  | 163 |     $guestrole       = (int)$CFG->guestroleid;
 | 
        
           |  |  | 164 |     $defaultfproleid = (int)$CFG->defaultfrontpageroleid;
 | 
        
           |  |  | 165 |   | 
        
           |  |  | 166 |     mtrace("Running daily statistics gathering, starting at $timestart:");
 | 
        
           |  |  | 167 |     \core\cron::trace_time_and_memory();
 | 
        
           |  |  | 168 |   | 
        
           |  |  | 169 |     $days  = 0;
 | 
        
           |  |  | 170 |     $total = 0;
 | 
        
           |  |  | 171 |     $failed  = false; // failed stats flag
 | 
        
           |  |  | 172 |     $timeout = false;
 | 
        
           |  |  | 173 |   | 
        
           |  |  | 174 |     if (!stats_temp_table_create()) {
 | 
        
           |  |  | 175 |         $days = 1;
 | 
        
           |  |  | 176 |         $failed = true;
 | 
        
           |  |  | 177 |     }
 | 
        
           |  |  | 178 |     mtrace('Temporary tables created');
 | 
        
           |  |  | 179 |   | 
        
           |  |  | 180 |     if(!stats_temp_table_setup()) {
 | 
        
           |  |  | 181 |         $days = 1;
 | 
        
           |  |  | 182 |         $failed = true;
 | 
        
           |  |  | 183 |     }
 | 
        
           |  |  | 184 |     mtrace('Enrolments calculated');
 | 
        
           |  |  | 185 |   | 
        
           |  |  | 186 |     $totalactiveusers = $DB->count_records('user', array('deleted' => '0'));
 | 
        
           |  |  | 187 |   | 
        
           |  |  | 188 |     while (!$failed && ($now > $nextmidnight)) {
 | 
        
           |  |  | 189 |         if ($days >= $maxdays) {
 | 
        
           |  |  | 190 |             $timeout = true;
 | 
        
           |  |  | 191 |             break;
 | 
        
           |  |  | 192 |         }
 | 
        
           |  |  | 193 |   | 
        
           |  |  | 194 |         $days++;
 | 
        
           |  |  | 195 |         core_php_time_limit::raise($timeout - 200);
 | 
        
           |  |  | 196 |   | 
        
           |  |  | 197 |         if ($days > 1) {
 | 
        
           |  |  | 198 |             // move the lock
 | 
        
           |  |  | 199 |             set_cron_lock('statsrunning', time() + $timeout, true);
 | 
        
           |  |  | 200 |         }
 | 
        
           |  |  | 201 |   | 
        
           |  |  | 202 |         $daystart = time();
 | 
        
           |  |  | 203 |   | 
        
           |  |  | 204 |         stats_progress('init');
 | 
        
           |  |  | 205 |   | 
        
           |  |  | 206 |         if (!stats_temp_table_fill($timestart, $nextmidnight)) {
 | 
        
           |  |  | 207 |             $failed = true;
 | 
        
           |  |  | 208 |             break;
 | 
        
           |  |  | 209 |         }
 | 
        
           |  |  | 210 |   | 
        
           |  |  | 211 |         // Find out if any logs available for this day
 | 
        
           |  |  | 212 |         $sql = "SELECT 'x' FROM {temp_log1} l";
 | 
        
           |  |  | 213 |         $logspresent = $DB->get_records_sql($sql, null, 0, 1);
 | 
        
           |  |  | 214 |   | 
        
           |  |  | 215 |         if ($logspresent) {
 | 
        
           |  |  | 216 |             // Insert blank record to force Query 10 to generate additional row when no logs for
 | 
        
           |  |  | 217 |             // the site with userid 0 exist.  Added for backwards compatibility.
 | 
        
           |  |  | 218 |             $DB->insert_record('temp_log1', array('userid' => 0, 'course' => SITEID, 'action' => ''));
 | 
        
           |  |  | 219 |         }
 | 
        
           |  |  | 220 |   | 
        
           |  |  | 221 |         // Calculate the number of active users today
 | 
        
           |  |  | 222 |         $sql = 'SELECT COUNT(DISTINCT u.id)
 | 
        
           |  |  | 223 |                   FROM {user} u
 | 
        
           |  |  | 224 |                   JOIN {temp_log1} l ON l.userid = u.id
 | 
        
           |  |  | 225 |                  WHERE u.deleted = 0';
 | 
        
           |  |  | 226 |         $dailyactiveusers = $DB->count_records_sql($sql);
 | 
        
           |  |  | 227 |   | 
        
           |  |  | 228 |         stats_progress('0');
 | 
        
           |  |  | 229 |   | 
        
           |  |  | 230 |         // Process login info first
 | 
        
           |  |  | 231 |         // Note: PostgreSQL doesn't like aliases in HAVING clauses
 | 
        
           |  |  | 232 |         $sql = "INSERT INTO {temp_stats_user_daily}
 | 
        
           |  |  | 233 |                             (stattype, timeend, courseid, userid, statsreads)
 | 
        
           |  |  | 234 |   | 
        
           |  |  | 235 |                 SELECT 'logins', $nextmidnight AS timeend, ".SITEID." AS courseid,
 | 
        
           |  |  | 236 |                         userid, COUNT(id) AS statsreads
 | 
        
           |  |  | 237 |                   FROM {temp_log1} l
 | 
        
           |  |  | 238 |                  WHERE action = 'login'
 | 
        
           |  |  | 239 |               GROUP BY userid
 | 
        
           |  |  | 240 |                 HAVING COUNT(id) > 0";
 | 
        
           |  |  | 241 |   | 
        
           |  |  | 242 |         if ($logspresent && !stats_run_query($sql)) {
 | 
        
           |  |  | 243 |             $failed = true;
 | 
        
           |  |  | 244 |             break;
 | 
        
           |  |  | 245 |         }
 | 
        
           |  |  | 246 |         $DB->update_temp_table_stats();
 | 
        
           |  |  | 247 |   | 
        
           |  |  | 248 |         stats_progress('1');
 | 
        
           |  |  | 249 |   | 
        
           |  |  | 250 |         $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 251 |   | 
        
           |  |  | 252 |                 SELECT 'logins' AS stattype, $nextmidnight AS timeend, ".SITEID." AS courseid, 0,
 | 
        
           |  |  | 253 |                        COALESCE(SUM(statsreads), 0) as stat1, COUNT('x') as stat2
 | 
        
           |  |  | 254 |                   FROM {temp_stats_user_daily}
 | 
        
           |  |  | 255 |                  WHERE stattype = 'logins' AND timeend = $nextmidnight";
 | 
        
           |  |  | 256 |   | 
        
           |  |  | 257 |         if ($logspresent && !stats_run_query($sql)) {
 | 
        
           |  |  | 258 |             $failed = true;
 | 
        
           |  |  | 259 |             break;
 | 
        
           |  |  | 260 |         }
 | 
        
           |  |  | 261 |         stats_progress('2');
 | 
        
           |  |  | 262 |   | 
        
           |  |  | 263 |   | 
        
           |  |  | 264 |         // Enrolments and active enrolled users
 | 
        
           |  |  | 265 |         //
 | 
        
           |  |  | 266 |         // Unfortunately, we do not know how many users were registered
 | 
        
           |  |  | 267 |         // at given times in history :-(
 | 
        
           |  |  | 268 |         // - stat1: enrolled users
 | 
        
           |  |  | 269 |         // - stat2: enrolled users active in this period
 | 
        
           |  |  | 270 |         // - SITEID is special case here, because it's all about default enrolment
 | 
        
           |  |  | 271 |         //   in that case, we'll count non-deleted users.
 | 
        
           |  |  | 272 |         //
 | 
        
           |  |  | 273 |   | 
        
           |  |  | 274 |         $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 275 |   | 
        
           |  |  | 276 |                 SELECT 'enrolments' as stattype, $nextmidnight as timeend, courseid, roleid,
 | 
        
           |  |  | 277 |                         COUNT(DISTINCT userid) as stat1, 0 as stat2
 | 
        
           |  |  | 278 |                   FROM {temp_enroled}
 | 
        
           |  |  | 279 |               GROUP BY courseid, roleid";
 | 
        
           |  |  | 280 |   | 
        
           |  |  | 281 |         if (!stats_run_query($sql)) {
 | 
        
           |  |  | 282 |             $failed = true;
 | 
        
           |  |  | 283 |             break;
 | 
        
           |  |  | 284 |         }
 | 
        
           |  |  | 285 |         stats_progress('3');
 | 
        
           |  |  | 286 |   | 
        
           |  |  | 287 |         // Set stat2 to the number distinct users with role assignments in the course that were active
 | 
        
           |  |  | 288 |         // using table alias in UPDATE does not work in pg < 8.2
 | 
        
           |  |  | 289 |         $sql = "UPDATE {temp_stats_daily}
 | 
        
           |  |  | 290 |                    SET stat2 = (
 | 
        
           |  |  | 291 |   | 
        
           |  |  | 292 |                     SELECT COUNT(DISTINCT userid)
 | 
        
           |  |  | 293 |                       FROM {temp_enroled} te
 | 
        
           |  |  | 294 |                      WHERE roleid = {temp_stats_daily}.roleid
 | 
        
           |  |  | 295 |                        AND courseid = {temp_stats_daily}.courseid
 | 
        
           |  |  | 296 |                        AND EXISTS (
 | 
        
           |  |  | 297 |   | 
        
           |  |  | 298 |                         SELECT 'x'
 | 
        
           |  |  | 299 |                           FROM {temp_log1} l
 | 
        
           |  |  | 300 |                          WHERE l.course = {temp_stats_daily}.courseid
 | 
        
           |  |  | 301 |                            AND l.userid = te.userid
 | 
        
           |  |  | 302 |                                   )
 | 
        
           |  |  | 303 |                                )
 | 
        
           |  |  | 304 |                  WHERE {temp_stats_daily}.stattype = 'enrolments'
 | 
        
           |  |  | 305 |                    AND {temp_stats_daily}.timeend = $nextmidnight
 | 
        
           |  |  | 306 |                    AND {temp_stats_daily}.courseid IN (
 | 
        
           |  |  | 307 |   | 
        
           |  |  | 308 |                     SELECT DISTINCT course FROM {temp_log2})";
 | 
        
           |  |  | 309 |   | 
        
           |  |  | 310 |         if ($logspresent && !stats_run_query($sql, array('courselevel'=>CONTEXT_COURSE))) {
 | 
        
           |  |  | 311 |             $failed = true;
 | 
        
           |  |  | 312 |             break;
 | 
        
           |  |  | 313 |         }
 | 
        
           |  |  | 314 |         stats_progress('4');
 | 
        
           |  |  | 315 |   | 
        
           |  |  | 316 |         // Now get course total enrolments (roleid==0) - except frontpage
 | 
        
           |  |  | 317 |         $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 318 |   | 
        
           |  |  | 319 |                 SELECT 'enrolments', $nextmidnight AS timeend, te.courseid AS courseid, 0 AS roleid,
 | 
        
           |  |  | 320 |                        COUNT(DISTINCT userid) AS stat1, 0 AS stat2
 | 
        
           |  |  | 321 |                   FROM {temp_enroled} te
 | 
        
           |  |  | 322 |               GROUP BY courseid
 | 
        
           |  |  | 323 |                 HAVING COUNT(DISTINCT userid) > 0";
 | 
        
           |  |  | 324 |   | 
        
           |  |  | 325 |         if ($logspresent && !stats_run_query($sql)) {
 | 
        
           |  |  | 326 |             $failed = true;
 | 
        
           |  |  | 327 |             break;
 | 
        
           |  |  | 328 |         }
 | 
        
           |  |  | 329 |         stats_progress('5');
 | 
        
           |  |  | 330 |   | 
        
           |  |  | 331 |         // Set stat 2 to the number of enrolled users who were active in the course
 | 
        
           |  |  | 332 |         $sql = "UPDATE {temp_stats_daily}
 | 
        
           |  |  | 333 |                    SET stat2 = (
 | 
        
           |  |  | 334 |   | 
        
           |  |  | 335 |                     SELECT COUNT(DISTINCT te.userid)
 | 
        
           |  |  | 336 |                       FROM {temp_enroled} te
 | 
        
           |  |  | 337 |                      WHERE te.courseid = {temp_stats_daily}.courseid
 | 
        
           |  |  | 338 |                        AND EXISTS (
 | 
        
           |  |  | 339 |   | 
        
           |  |  | 340 |                         SELECT 'x'
 | 
        
           |  |  | 341 |                           FROM {temp_log1} l
 | 
        
           |  |  | 342 |                          WHERE l.course = {temp_stats_daily}.courseid
 | 
        
           |  |  | 343 |                            AND l.userid = te.userid
 | 
        
           |  |  | 344 |                                   )
 | 
        
           |  |  | 345 |                                )
 | 
        
           |  |  | 346 |   | 
        
           |  |  | 347 |                  WHERE {temp_stats_daily}.stattype = 'enrolments'
 | 
        
           |  |  | 348 |                    AND {temp_stats_daily}.timeend = $nextmidnight
 | 
        
           |  |  | 349 |                    AND {temp_stats_daily}.roleid = 0
 | 
        
           |  |  | 350 |                    AND {temp_stats_daily}.courseid IN (
 | 
        
           |  |  | 351 |   | 
        
           |  |  | 352 |                     SELECT l.course
 | 
        
           |  |  | 353 |                       FROM {temp_log2} l
 | 
        
           |  |  | 354 |                      WHERE l.course <> ".SITEID.")";
 | 
        
           |  |  | 355 |   | 
        
           |  |  | 356 |         if ($logspresent && !stats_run_query($sql, array())) {
 | 
        
           |  |  | 357 |             $failed = true;
 | 
        
           |  |  | 358 |             break;
 | 
        
           |  |  | 359 |         }
 | 
        
           |  |  | 360 |         stats_progress('6');
 | 
        
           |  |  | 361 |   | 
        
           |  |  | 362 |         // Frontpage(==site) enrolments total
 | 
        
           |  |  | 363 |         $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 364 |   | 
        
           |  |  | 365 |                 SELECT 'enrolments', $nextmidnight, ".SITEID.", 0, $totalactiveusers AS stat1,
 | 
        
           |  |  | 366 |                        $dailyactiveusers AS stat2" .
 | 
        
           |  |  | 367 |                 $DB->sql_null_from_clause();
 | 
        
           |  |  | 368 |   | 
        
           |  |  | 369 |         if ($logspresent && !stats_run_query($sql)) {
 | 
        
           |  |  | 370 |             $failed = true;
 | 
        
           |  |  | 371 |             break;
 | 
        
           |  |  | 372 |         }
 | 
        
           |  |  | 373 |         // The steps up until this point, all add to {temp_stats_daily} and don't use new tables.
 | 
        
           |  |  | 374 |         // There is no point updating statistics as they won't be used until the DELETE below.
 | 
        
           |  |  | 375 |         $DB->update_temp_table_stats();
 | 
        
           |  |  | 376 |   | 
        
           |  |  | 377 |         stats_progress('7');
 | 
        
           |  |  | 378 |   | 
        
           |  |  | 379 |         // Default frontpage role enrolments are all site users (not deleted)
 | 
        
           |  |  | 380 |         if ($defaultfproleid) {
 | 
        
           |  |  | 381 |             // first remove default frontpage role counts if created by previous query
 | 
        
           |  |  | 382 |             $sql = "DELETE
 | 
        
           |  |  | 383 |                       FROM {temp_stats_daily}
 | 
        
           |  |  | 384 |                      WHERE stattype = 'enrolments'
 | 
        
           |  |  | 385 |                        AND courseid = ".SITEID."
 | 
        
           |  |  | 386 |                        AND roleid = $defaultfproleid
 | 
        
           |  |  | 387 |                        AND timeend = $nextmidnight";
 | 
        
           |  |  | 388 |   | 
        
           |  |  | 389 |             if ($logspresent && !stats_run_query($sql)) {
 | 
        
           |  |  | 390 |                 $failed = true;
 | 
        
           |  |  | 391 |                 break;
 | 
        
           |  |  | 392 |             }
 | 
        
           |  |  | 393 |             stats_progress('8');
 | 
        
           |  |  | 394 |   | 
        
           |  |  | 395 |             $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 396 |   | 
        
           |  |  | 397 |                     SELECT 'enrolments', $nextmidnight, ".SITEID.", $defaultfproleid,
 | 
        
           |  |  | 398 |                            $totalactiveusers AS stat1, $dailyactiveusers AS stat2" .
 | 
        
           |  |  | 399 |                     $DB->sql_null_from_clause();
 | 
        
           |  |  | 400 |   | 
        
           |  |  | 401 |             if ($logspresent && !stats_run_query($sql)) {
 | 
        
           |  |  | 402 |                 $failed = true;
 | 
        
           |  |  | 403 |                 break;
 | 
        
           |  |  | 404 |             }
 | 
        
           |  |  | 405 |             stats_progress('9');
 | 
        
           |  |  | 406 |   | 
        
           |  |  | 407 |         } else {
 | 
        
           |  |  | 408 |             stats_progress('x');
 | 
        
           |  |  | 409 |             stats_progress('x');
 | 
        
           |  |  | 410 |         }
 | 
        
           |  |  | 411 |   | 
        
           |  |  | 412 |   | 
        
           |  |  | 413 |         /// individual user stats (including not-logged-in) in each course, this is slow - reuse this data if possible
 | 
        
           |  |  | 414 |         list($viewactionssql, $params1) = $DB->get_in_or_equal($viewactions, SQL_PARAMS_NAMED, 'view');
 | 
        
           |  |  | 415 |         list($postactionssql, $params2) = $DB->get_in_or_equal($postactions, SQL_PARAMS_NAMED, 'post');
 | 
        
           |  |  | 416 |         $sql = "INSERT INTO {temp_stats_user_daily} (stattype, timeend, courseid, userid, statsreads, statswrites)
 | 
        
           |  |  | 417 |   | 
        
           |  |  | 418 |                 SELECT 'activity' AS stattype, $nextmidnight AS timeend, course AS courseid, userid,
 | 
        
           |  |  | 419 |                        SUM(CASE WHEN action $viewactionssql THEN 1 ELSE 0 END) AS statsreads,
 | 
        
           |  |  | 420 |                        SUM(CASE WHEN action $postactionssql THEN 1 ELSE 0 END) AS statswrites
 | 
        
           |  |  | 421 |                   FROM {temp_log1} l
 | 
        
           |  |  | 422 |               GROUP BY userid, course";
 | 
        
           |  |  | 423 |   | 
        
           |  |  | 424 |         if ($logspresent && !stats_run_query($sql, array_merge($params1, $params2))) {
 | 
        
           |  |  | 425 |             $failed = true;
 | 
        
           |  |  | 426 |             break;
 | 
        
           |  |  | 427 |         }
 | 
        
           |  |  | 428 |         stats_progress('10');
 | 
        
           |  |  | 429 |   | 
        
           |  |  | 430 |   | 
        
           |  |  | 431 |         /// How many view/post actions in each course total
 | 
        
           |  |  | 432 |         $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 433 |   | 
        
           |  |  | 434 |                 SELECT 'activity' AS stattype, $nextmidnight AS timeend, c.id AS courseid, 0,
 | 
        
           |  |  | 435 |                        SUM(CASE WHEN l.action $viewactionssql THEN 1 ELSE 0 END) AS stat1,
 | 
        
           |  |  | 436 |                        SUM(CASE WHEN l.action $postactionssql THEN 1 ELSE 0 END) AS stat2
 | 
        
           |  |  | 437 |                   FROM {course} c, {temp_log1} l
 | 
        
           |  |  | 438 |                  WHERE l.course = c.id
 | 
        
           |  |  | 439 |               GROUP BY c.id";
 | 
        
           |  |  | 440 |   | 
        
           |  |  | 441 |         if ($logspresent && !stats_run_query($sql, array_merge($params1, $params2))) {
 | 
        
           |  |  | 442 |             $failed = true;
 | 
        
           |  |  | 443 |             break;
 | 
        
           |  |  | 444 |         }
 | 
        
           |  |  | 445 |         stats_progress('11');
 | 
        
           |  |  | 446 |   | 
        
           |  |  | 447 |   | 
        
           |  |  | 448 |         /// how many view actions for each course+role - excluding guests and frontpage
 | 
        
           |  |  | 449 |   | 
        
           |  |  | 450 |         $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 451 |   | 
        
           |  |  | 452 |                 SELECT 'activity', $nextmidnight AS timeend, courseid, roleid, SUM(statsreads), SUM(statswrites)
 | 
        
           |  |  | 453 |                   FROM (
 | 
        
           |  |  | 454 |   | 
        
           |  |  | 455 |                     SELECT pl.courseid, pl.roleid, sud.statsreads, sud.statswrites
 | 
        
           |  |  | 456 |                       FROM {temp_stats_user_daily} sud, (
 | 
        
           |  |  | 457 |   | 
        
           |  |  | 458 |                         SELECT DISTINCT te.userid, te.roleid, te.courseid
 | 
        
           |  |  | 459 |                           FROM {temp_enroled} te
 | 
        
           |  |  | 460 |                          WHERE te.roleid <> $guestrole
 | 
        
           |  |  | 461 |                            AND te.userid <> $guest
 | 
        
           |  |  | 462 |                                                         ) pl
 | 
        
           |  |  | 463 |   | 
        
           |  |  | 464 |                      WHERE sud.userid = pl.userid
 | 
        
           |  |  | 465 |                        AND sud.courseid = pl.courseid
 | 
        
           |  |  | 466 |                        AND sud.timeend = $nextmidnight
 | 
        
           |  |  | 467 |                        AND sud.stattype='activity'
 | 
        
           |  |  | 468 |                        ) inline_view
 | 
        
           |  |  | 469 |   | 
        
           |  |  | 470 |               GROUP BY courseid, roleid
 | 
        
           |  |  | 471 |                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
 | 
        
           |  |  | 472 |   | 
        
           |  |  | 473 |         if ($logspresent && !stats_run_query($sql, array('courselevel'=>CONTEXT_COURSE))) {
 | 
        
           |  |  | 474 |             $failed = true;
 | 
        
           |  |  | 475 |             break;
 | 
        
           |  |  | 476 |         }
 | 
        
           |  |  | 477 |         stats_progress('12');
 | 
        
           |  |  | 478 |   | 
        
           |  |  | 479 |         /// how many view actions from guests only in each course - excluding frontpage
 | 
        
           |  |  | 480 |         /// normal users may enter course with temporary guest access too
 | 
        
           |  |  | 481 |   | 
        
           |  |  | 482 |         $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 483 |   | 
        
           |  |  | 484 |                 SELECT 'activity', $nextmidnight AS timeend, courseid, $guestrole AS roleid,
 | 
        
           |  |  | 485 |                        SUM(statsreads), SUM(statswrites)
 | 
        
           |  |  | 486 |                   FROM (
 | 
        
           |  |  | 487 |   | 
        
           |  |  | 488 |                     SELECT sud.courseid, sud.statsreads, sud.statswrites
 | 
        
           |  |  | 489 |                       FROM {temp_stats_user_daily} sud
 | 
        
           |  |  | 490 |                      WHERE sud.timeend = $nextmidnight
 | 
        
           |  |  | 491 |                        AND sud.courseid <> ".SITEID."
 | 
        
           |  |  | 492 |                        AND sud.stattype='activity'
 | 
        
           |  |  | 493 |                        AND (sud.userid = $guest OR sud.userid NOT IN (
 | 
        
           |  |  | 494 |   | 
        
           |  |  | 495 |                         SELECT userid
 | 
        
           |  |  | 496 |                           FROM {temp_enroled} te
 | 
        
           |  |  | 497 |                          WHERE te.courseid = sud.courseid
 | 
        
           |  |  | 498 |                                                                      ))
 | 
        
           |  |  | 499 |                        ) inline_view
 | 
        
           |  |  | 500 |   | 
        
           |  |  | 501 |               GROUP BY courseid
 | 
        
           |  |  | 502 |                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
 | 
        
           |  |  | 503 |   | 
        
           |  |  | 504 |         if ($logspresent && !stats_run_query($sql, array())) {
 | 
        
           |  |  | 505 |             $failed = true;
 | 
        
           |  |  | 506 |             break;
 | 
        
           |  |  | 507 |         }
 | 
        
           |  |  | 508 |         stats_progress('13');
 | 
        
           |  |  | 509 |   | 
        
           |  |  | 510 |   | 
        
           |  |  | 511 |         /// How many view actions for each role on frontpage - excluding guests, not-logged-in and default frontpage role
 | 
        
           |  |  | 512 |         $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 513 |   | 
        
           |  |  | 514 |                 SELECT 'activity', $nextmidnight AS timeend, courseid, roleid,
 | 
        
           |  |  | 515 |                        SUM(statsreads), SUM(statswrites)
 | 
        
           |  |  | 516 |                   FROM (
 | 
        
           |  |  | 517 |                     SELECT pl.courseid, pl.roleid, sud.statsreads, sud.statswrites
 | 
        
           |  |  | 518 |                       FROM {temp_stats_user_daily} sud, (
 | 
        
           |  |  | 519 |   | 
        
           |  |  | 520 |                         SELECT DISTINCT ra.userid, ra.roleid, c.instanceid AS courseid
 | 
        
           |  |  | 521 |                           FROM {role_assignments} ra
 | 
        
           |  |  | 522 |                           JOIN {context} c ON c.id = ra.contextid
 | 
        
           |  |  | 523 |                          WHERE ra.contextid = :fpcontext
 | 
        
           |  |  | 524 |                            AND ra.roleid <> $defaultfproleid
 | 
        
           |  |  | 525 |                            AND ra.roleid <> $guestrole
 | 
        
           |  |  | 526 |                            AND ra.userid <> $guest
 | 
        
           |  |  | 527 |                                                    ) pl
 | 
        
           |  |  | 528 |                      WHERE sud.userid = pl.userid
 | 
        
           |  |  | 529 |                        AND sud.courseid = pl.courseid
 | 
        
           |  |  | 530 |                        AND sud.timeend = $nextmidnight
 | 
        
           |  |  | 531 |                        AND sud.stattype='activity'
 | 
        
           |  |  | 532 |                        ) inline_view
 | 
        
           |  |  | 533 |   | 
        
           |  |  | 534 |               GROUP BY courseid, roleid
 | 
        
           |  |  | 535 |                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
 | 
        
           |  |  | 536 |   | 
        
           |  |  | 537 |         if ($logspresent && !stats_run_query($sql, array('fpcontext'=>$fpcontext->id))) {
 | 
        
           |  |  | 538 |             $failed = true;
 | 
        
           |  |  | 539 |             break;
 | 
        
           |  |  | 540 |         }
 | 
        
           |  |  | 541 |         stats_progress('14');
 | 
        
           |  |  | 542 |   | 
        
           |  |  | 543 |   | 
        
           |  |  | 544 |         // How many view actions for default frontpage role on frontpage only
 | 
        
           |  |  | 545 |         $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 546 |   | 
        
           |  |  | 547 |                 SELECT 'activity', timeend, courseid, $defaultfproleid AS roleid,
 | 
        
           |  |  | 548 |                        SUM(statsreads), SUM(statswrites)
 | 
        
           |  |  | 549 |                   FROM (
 | 
        
           |  |  | 550 |                     SELECT sud.timeend AS timeend, sud.courseid, sud.statsreads, sud.statswrites
 | 
        
           |  |  | 551 |                       FROM {temp_stats_user_daily} sud
 | 
        
           |  |  | 552 |                      WHERE sud.timeend = :nextm
 | 
        
           |  |  | 553 |                        AND sud.courseid = :siteid
 | 
        
           |  |  | 554 |                        AND sud.stattype='activity'
 | 
        
           |  |  | 555 |                        AND sud.userid <> $guest
 | 
        
           |  |  | 556 |                        AND sud.userid <> 0
 | 
        
           |  |  | 557 |                        AND sud.userid NOT IN (
 | 
        
           |  |  | 558 |   | 
        
           |  |  | 559 |                         SELECT ra.userid
 | 
        
           |  |  | 560 |                           FROM {role_assignments} ra
 | 
        
           |  |  | 561 |                          WHERE ra.roleid <> $guestrole
 | 
        
           |  |  | 562 |                            AND ra.roleid <> $defaultfproleid
 | 
        
           |  |  | 563 |                            AND ra.contextid = :fpcontext)
 | 
        
           |  |  | 564 |                        ) inline_view
 | 
        
           |  |  | 565 |   | 
        
           |  |  | 566 |               GROUP BY timeend, courseid
 | 
        
           |  |  | 567 |                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
 | 
        
           |  |  | 568 |   | 
        
           |  |  | 569 |         if ($logspresent && !stats_run_query($sql, array('fpcontext'=>$fpcontext->id, 'siteid'=>SITEID, 'nextm'=>$nextmidnight))) {
 | 
        
           |  |  | 570 |             $failed = true;
 | 
        
           |  |  | 571 |             break;
 | 
        
           |  |  | 572 |         }
 | 
        
           |  |  | 573 |         $DB->update_temp_table_stats();
 | 
        
           |  |  | 574 |         stats_progress('15');
 | 
        
           |  |  | 575 |   | 
        
           |  |  | 576 |         // How many view actions for guests or not-logged-in on frontpage
 | 
        
           |  |  | 577 |         $sql = "INSERT INTO {temp_stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 578 |   | 
        
           |  |  | 579 |                 SELECT stattype, timeend, courseid, $guestrole AS roleid,
 | 
        
           |  |  | 580 |                        SUM(statsreads) AS stat1, SUM(statswrites) AS stat2
 | 
        
           |  |  | 581 |                   FROM (
 | 
        
           |  |  | 582 |                     SELECT sud.stattype, sud.timeend, sud.courseid,
 | 
        
           |  |  | 583 |                            sud.statsreads, sud.statswrites
 | 
        
           |  |  | 584 |                       FROM {temp_stats_user_daily} sud
 | 
        
           |  |  | 585 |                      WHERE (sud.userid = $guest OR sud.userid = 0)
 | 
        
           |  |  | 586 |                        AND sud.timeend = $nextmidnight
 | 
        
           |  |  | 587 |                        AND sud.courseid = ".SITEID."
 | 
        
           |  |  | 588 |                        AND sud.stattype='activity'
 | 
        
           |  |  | 589 |                        ) inline_view
 | 
        
           |  |  | 590 |                  GROUP BY stattype, timeend, courseid
 | 
        
           |  |  | 591 |                  HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
 | 
        
           |  |  | 592 |   | 
        
           |  |  | 593 |         if ($logspresent && !stats_run_query($sql)) {
 | 
        
           |  |  | 594 |             $failed = true;
 | 
        
           |  |  | 595 |             break;
 | 
        
           |  |  | 596 |         }
 | 
        
           |  |  | 597 |         stats_progress('16');
 | 
        
           |  |  | 598 |   | 
        
           |  |  | 599 |         stats_temp_table_clean();
 | 
        
           |  |  | 600 |   | 
        
           |  |  | 601 |         stats_progress('out');
 | 
        
           |  |  | 602 |   | 
        
           |  |  | 603 |         // remember processed days
 | 
        
           |  |  | 604 |         set_config('statslastdaily', $nextmidnight);
 | 
        
           |  |  | 605 |         $elapsed = time()-$daystart;
 | 
        
           |  |  | 606 |         mtrace("  finished until $nextmidnight: ".userdate($nextmidnight)." (in $elapsed s)");
 | 
        
           |  |  | 607 |         $total += $elapsed;
 | 
        
           |  |  | 608 |   | 
        
           |  |  | 609 |         $timestart    = $nextmidnight;
 | 
        
           |  |  | 610 |         $nextmidnight = stats_get_next_day_start($nextmidnight);
 | 
        
           |  |  | 611 |     }
 | 
        
           |  |  | 612 |   | 
        
           |  |  | 613 |     stats_temp_table_drop();
 | 
        
           |  |  | 614 |   | 
        
           |  |  | 615 |     set_cron_lock('statsrunning', null);
 | 
        
           |  |  | 616 |   | 
        
           |  |  | 617 |     if ($failed) {
 | 
        
           |  |  | 618 |         $days--;
 | 
        
           |  |  | 619 |         mtrace("...error occurred, completed $days days of statistics in {$total} s.");
 | 
        
           |  |  | 620 |         return false;
 | 
        
           |  |  | 621 |   | 
        
           |  |  | 622 |     } else if ($timeout) {
 | 
        
           |  |  | 623 |         mtrace("...stopping early, reached maximum number of $maxdays days ({$total} s) - will continue next time.");
 | 
        
           |  |  | 624 |         return false;
 | 
        
           |  |  | 625 |   | 
        
           |  |  | 626 |     } else {
 | 
        
           |  |  | 627 |         mtrace("...completed $days days of statistics in {$total} s.");
 | 
        
           |  |  | 628 |         return true;
 | 
        
           |  |  | 629 |     }
 | 
        
           |  |  | 630 | }
 | 
        
           |  |  | 631 |   | 
        
           |  |  | 632 |   | 
        
           |  |  | 633 | /**
 | 
        
           |  |  | 634 |  * Execute weekly statistics gathering
 | 
        
           |  |  | 635 |  * @return boolean success
 | 
        
           |  |  | 636 |  */
 | 
        
           |  |  | 637 | function stats_cron_weekly() {
 | 
        
           |  |  | 638 |     global $CFG, $DB;
 | 
        
           |  |  | 639 |     require_once($CFG->libdir.'/adminlib.php');
 | 
        
           |  |  | 640 |   | 
        
           |  |  | 641 |     $now = time();
 | 
        
           |  |  | 642 |   | 
        
           |  |  | 643 |     // read last execution date from db
 | 
        
           |  |  | 644 |     if (!$timestart = get_config(NULL, 'statslastweekly')) {
 | 
        
           |  |  | 645 |         $timestart = stats_get_base_daily(stats_get_start_from('weekly'));
 | 
        
           |  |  | 646 |         set_config('statslastweekly', $timestart);
 | 
        
           |  |  | 647 |     }
 | 
        
           |  |  | 648 |   | 
        
           |  |  | 649 |     $nextstartweek = stats_get_next_week_start($timestart);
 | 
        
           |  |  | 650 |   | 
        
           |  |  | 651 |     // are there any weeks that need to be processed?
 | 
        
           |  |  | 652 |     if ($now < $nextstartweek) {
 | 
        
           |  |  | 653 |         return true; // everything ok and up-to-date
 | 
        
           |  |  | 654 |     }
 | 
        
           |  |  | 655 |   | 
        
           |  |  | 656 |     $timeout = empty($CFG->statsmaxruntime) ? 60*60*24 : $CFG->statsmaxruntime;
 | 
        
           |  |  | 657 |   | 
        
           |  |  | 658 |     if (!set_cron_lock('statsrunning', $now + $timeout)) {
 | 
        
           |  |  | 659 |         return false;
 | 
        
           |  |  | 660 |     }
 | 
        
           |  |  | 661 |   | 
        
           |  |  | 662 |     // fisrt delete entries that should not be there yet
 | 
        
           |  |  | 663 |     $DB->delete_records_select('stats_weekly',      "timeend > $timestart");
 | 
        
           |  |  | 664 |     $DB->delete_records_select('stats_user_weekly', "timeend > $timestart");
 | 
        
           |  |  | 665 |   | 
        
           |  |  | 666 |     mtrace("Running weekly statistics gathering, starting at $timestart:");
 | 
        
           |  |  | 667 |     \core\cron::trace_time_and_memory();
 | 
        
           |  |  | 668 |   | 
        
           |  |  | 669 |     $weeks = 0;
 | 
        
           |  |  | 670 |     while ($now > $nextstartweek) {
 | 
        
           |  |  | 671 |         core_php_time_limit::raise($timeout - 200);
 | 
        
           |  |  | 672 |         $weeks++;
 | 
        
           |  |  | 673 |   | 
        
           |  |  | 674 |         if ($weeks > 1) {
 | 
        
           |  |  | 675 |             // move the lock
 | 
        
           |  |  | 676 |             set_cron_lock('statsrunning', time() + $timeout, true);
 | 
        
           |  |  | 677 |         }
 | 
        
           |  |  | 678 |   | 
        
           |  |  | 679 |         $stattimesql = "timeend > $timestart AND timeend <= $nextstartweek";
 | 
        
           |  |  | 680 |   | 
        
           |  |  | 681 |         $weekstart = time();
 | 
        
           |  |  | 682 |         stats_progress('init');
 | 
        
           |  |  | 683 |   | 
        
           |  |  | 684 |     /// process login info first
 | 
        
           |  |  | 685 |         $sql = "INSERT INTO {stats_user_weekly} (stattype, timeend, courseid, userid, statsreads)
 | 
        
           |  |  | 686 |   | 
        
           |  |  | 687 |                 SELECT 'logins', timeend, courseid, userid, SUM(statsreads)
 | 
        
           |  |  | 688 |                   FROM (
 | 
        
           |  |  | 689 |                            SELECT $nextstartweek AS timeend, courseid, userid, statsreads
 | 
        
           |  |  | 690 |                              FROM {stats_user_daily} sd
 | 
        
           |  |  | 691 |                             WHERE stattype = 'logins' AND $stattimesql
 | 
        
           |  |  | 692 |                        ) inline_view
 | 
        
           |  |  | 693 |               GROUP BY timeend, courseid, userid
 | 
        
           |  |  | 694 |                 HAVING SUM(statsreads) > 0";
 | 
        
           |  |  | 695 |   | 
        
           |  |  | 696 |         $DB->execute($sql);
 | 
        
           |  |  | 697 |   | 
        
           |  |  | 698 |         stats_progress('1');
 | 
        
           |  |  | 699 |   | 
        
           |  |  | 700 |         $sql = "INSERT INTO {stats_weekly} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 701 |   | 
        
           |  |  | 702 |                 SELECT 'logins' AS stattype, $nextstartweek AS timeend, ".SITEID." as courseid, 0,
 | 
        
           |  |  | 703 |                        COALESCE((SELECT SUM(statsreads)
 | 
        
           |  |  | 704 |                                    FROM {stats_user_weekly} s1
 | 
        
           |  |  | 705 |                                   WHERE s1.stattype = 'logins' AND timeend = $nextstartweek), 0) AS nstat1,
 | 
        
           |  |  | 706 |                        (SELECT COUNT('x')
 | 
        
           |  |  | 707 |                           FROM {stats_user_weekly} s2
 | 
        
           |  |  | 708 |                          WHERE s2.stattype = 'logins' AND timeend = $nextstartweek) AS nstat2" .
 | 
        
           |  |  | 709 |                 $DB->sql_null_from_clause();
 | 
        
           |  |  | 710 |   | 
        
           |  |  | 711 |         $DB->execute($sql);
 | 
        
           |  |  | 712 |   | 
        
           |  |  | 713 |         stats_progress('2');
 | 
        
           |  |  | 714 |   | 
        
           |  |  | 715 |     /// now enrolments averages
 | 
        
           |  |  | 716 |         $sql = "INSERT INTO {stats_weekly} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 717 |   | 
        
           |  |  | 718 |                 SELECT 'enrolments', ntimeend, courseid, roleid, " . $DB->sql_ceil('AVG(stat1)') . ", " . $DB->sql_ceil('AVG(stat2)') . "
 | 
        
           |  |  | 719 |                   FROM (
 | 
        
           |  |  | 720 |                            SELECT $nextstartweek AS ntimeend, courseid, roleid, stat1, stat2
 | 
        
           |  |  | 721 |                              FROM {stats_daily} sd
 | 
        
           |  |  | 722 |                             WHERE stattype = 'enrolments' AND $stattimesql
 | 
        
           |  |  | 723 |                        ) inline_view
 | 
        
           |  |  | 724 |               GROUP BY ntimeend, courseid, roleid";
 | 
        
           |  |  | 725 |   | 
        
           |  |  | 726 |         $DB->execute($sql);
 | 
        
           |  |  | 727 |   | 
        
           |  |  | 728 |         stats_progress('3');
 | 
        
           |  |  | 729 |   | 
        
           |  |  | 730 |     /// activity read/write averages
 | 
        
           |  |  | 731 |         $sql = "INSERT INTO {stats_weekly} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 732 |   | 
        
           |  |  | 733 |                 SELECT 'activity', ntimeend, courseid, roleid, SUM(stat1), SUM(stat2)
 | 
        
           |  |  | 734 |                   FROM (
 | 
        
           |  |  | 735 |                            SELECT $nextstartweek AS ntimeend, courseid, roleid, stat1, stat2
 | 
        
           |  |  | 736 |                              FROM {stats_daily}
 | 
        
           |  |  | 737 |                             WHERE stattype = 'activity' AND $stattimesql
 | 
        
           |  |  | 738 |                        ) inline_view
 | 
        
           |  |  | 739 |               GROUP BY ntimeend, courseid, roleid";
 | 
        
           |  |  | 740 |   | 
        
           |  |  | 741 |         $DB->execute($sql);
 | 
        
           |  |  | 742 |   | 
        
           |  |  | 743 |         stats_progress('4');
 | 
        
           |  |  | 744 |   | 
        
           |  |  | 745 |     /// user read/write averages
 | 
        
           |  |  | 746 |         $sql = "INSERT INTO {stats_user_weekly} (stattype, timeend, courseid, userid, statsreads, statswrites)
 | 
        
           |  |  | 747 |   | 
        
           |  |  | 748 |                 SELECT 'activity', ntimeend, courseid, userid, SUM(statsreads), SUM(statswrites)
 | 
        
           |  |  | 749 |                   FROM (
 | 
        
           |  |  | 750 |                            SELECT $nextstartweek AS ntimeend, courseid, userid, statsreads, statswrites
 | 
        
           |  |  | 751 |                              FROM {stats_user_daily}
 | 
        
           |  |  | 752 |                             WHERE stattype = 'activity' AND $stattimesql
 | 
        
           |  |  | 753 |                        ) inline_view
 | 
        
           |  |  | 754 |               GROUP BY ntimeend, courseid, userid";
 | 
        
           |  |  | 755 |   | 
        
           |  |  | 756 |         $DB->execute($sql);
 | 
        
           |  |  | 757 |   | 
        
           |  |  | 758 |         stats_progress('5');
 | 
        
           |  |  | 759 |   | 
        
           |  |  | 760 |         set_config('statslastweekly', $nextstartweek);
 | 
        
           |  |  | 761 |         $elapsed = time()-$weekstart;
 | 
        
           |  |  | 762 |         mtrace(" finished until $nextstartweek: ".userdate($nextstartweek) ." (in $elapsed s)");
 | 
        
           |  |  | 763 |   | 
        
           |  |  | 764 |         $timestart     = $nextstartweek;
 | 
        
           |  |  | 765 |         $nextstartweek = stats_get_next_week_start($nextstartweek);
 | 
        
           |  |  | 766 |     }
 | 
        
           |  |  | 767 |   | 
        
           |  |  | 768 |     set_cron_lock('statsrunning', null);
 | 
        
           |  |  | 769 |     mtrace("...completed $weeks weeks of statistics.");
 | 
        
           |  |  | 770 |     return true;
 | 
        
           |  |  | 771 | }
 | 
        
           |  |  | 772 |   | 
        
           |  |  | 773 | /**
 | 
        
           |  |  | 774 |  * Execute monthly statistics gathering
 | 
        
           |  |  | 775 |  * @return boolean success
 | 
        
           |  |  | 776 |  */
 | 
        
           |  |  | 777 | function stats_cron_monthly() {
 | 
        
           |  |  | 778 |     global $CFG, $DB;
 | 
        
           |  |  | 779 |     require_once($CFG->libdir.'/adminlib.php');
 | 
        
           |  |  | 780 |   | 
        
           |  |  | 781 |     $now = time();
 | 
        
           |  |  | 782 |   | 
        
           |  |  | 783 |     // read last execution date from db
 | 
        
           |  |  | 784 |     if (!$timestart = get_config(NULL, 'statslastmonthly')) {
 | 
        
           |  |  | 785 |         $timestart = stats_get_base_monthly(stats_get_start_from('monthly'));
 | 
        
           |  |  | 786 |         set_config('statslastmonthly', $timestart);
 | 
        
           |  |  | 787 |     }
 | 
        
           |  |  | 788 |   | 
        
           |  |  | 789 |     $nextstartmonth = stats_get_next_month_start($timestart);
 | 
        
           |  |  | 790 |   | 
        
           |  |  | 791 |     // are there any months that need to be processed?
 | 
        
           |  |  | 792 |     if ($now < $nextstartmonth) {
 | 
        
           |  |  | 793 |         return true; // everything ok and up-to-date
 | 
        
           |  |  | 794 |     }
 | 
        
           |  |  | 795 |   | 
        
           |  |  | 796 |     $timeout = empty($CFG->statsmaxruntime) ? 60*60*24 : $CFG->statsmaxruntime;
 | 
        
           |  |  | 797 |   | 
        
           |  |  | 798 |     if (!set_cron_lock('statsrunning', $now + $timeout)) {
 | 
        
           |  |  | 799 |         return false;
 | 
        
           |  |  | 800 |     }
 | 
        
           |  |  | 801 |   | 
        
           |  |  | 802 |     // fisr delete entries that should not be there yet
 | 
        
           |  |  | 803 |     $DB->delete_records_select('stats_monthly', "timeend > $timestart");
 | 
        
           |  |  | 804 |     $DB->delete_records_select('stats_user_monthly', "timeend > $timestart");
 | 
        
           |  |  | 805 |   | 
        
           |  |  | 806 |     $startmonth = stats_get_base_monthly($now);
 | 
        
           |  |  | 807 |   | 
        
           |  |  | 808 |   | 
        
           |  |  | 809 |     mtrace("Running monthly statistics gathering, starting at $timestart:");
 | 
        
           |  |  | 810 |     \core\cron::trace_time_and_memory();
 | 
        
           |  |  | 811 |   | 
        
           |  |  | 812 |     $months = 0;
 | 
        
           |  |  | 813 |     while ($now > $nextstartmonth) {
 | 
        
           |  |  | 814 |         core_php_time_limit::raise($timeout - 200);
 | 
        
           |  |  | 815 |         $months++;
 | 
        
           |  |  | 816 |   | 
        
           |  |  | 817 |         if ($months > 1) {
 | 
        
           |  |  | 818 |             // move the lock
 | 
        
           |  |  | 819 |             set_cron_lock('statsrunning', time() + $timeout, true);
 | 
        
           |  |  | 820 |         }
 | 
        
           |  |  | 821 |   | 
        
           |  |  | 822 |         $stattimesql = "timeend > $timestart AND timeend <= $nextstartmonth";
 | 
        
           |  |  | 823 |   | 
        
           |  |  | 824 |         $monthstart = time();
 | 
        
           |  |  | 825 |         stats_progress('init');
 | 
        
           |  |  | 826 |   | 
        
           |  |  | 827 |     /// process login info first
 | 
        
           |  |  | 828 |         $sql = "INSERT INTO {stats_user_monthly} (stattype, timeend, courseid, userid, statsreads)
 | 
        
           |  |  | 829 |   | 
        
           |  |  | 830 |                 SELECT 'logins', timeend, courseid, userid, SUM(statsreads)
 | 
        
           |  |  | 831 |                   FROM (
 | 
        
           |  |  | 832 |                            SELECT $nextstartmonth AS timeend, courseid, userid, statsreads
 | 
        
           |  |  | 833 |                              FROM {stats_user_daily} sd
 | 
        
           |  |  | 834 |                             WHERE stattype = 'logins' AND $stattimesql
 | 
        
           |  |  | 835 |                        ) inline_view
 | 
        
           |  |  | 836 |               GROUP BY timeend, courseid, userid
 | 
        
           |  |  | 837 |                 HAVING SUM(statsreads) > 0";
 | 
        
           |  |  | 838 |   | 
        
           |  |  | 839 |         $DB->execute($sql);
 | 
        
           |  |  | 840 |   | 
        
           |  |  | 841 |         stats_progress('1');
 | 
        
           |  |  | 842 |   | 
        
           |  |  | 843 |         $sql = "INSERT INTO {stats_monthly} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 844 |   | 
        
           |  |  | 845 |                 SELECT 'logins' AS stattype, $nextstartmonth AS timeend, ".SITEID." as courseid, 0,
 | 
        
           |  |  | 846 |                        COALESCE((SELECT SUM(statsreads)
 | 
        
           |  |  | 847 |                                    FROM {stats_user_monthly} s1
 | 
        
           |  |  | 848 |                                   WHERE s1.stattype = 'logins' AND timeend = $nextstartmonth), 0) AS nstat1,
 | 
        
           |  |  | 849 |                        (SELECT COUNT('x')
 | 
        
           |  |  | 850 |                           FROM {stats_user_monthly} s2
 | 
        
           |  |  | 851 |                          WHERE s2.stattype = 'logins' AND timeend = $nextstartmonth) AS nstat2" .
 | 
        
           |  |  | 852 |                 $DB->sql_null_from_clause();
 | 
        
           |  |  | 853 |   | 
        
           |  |  | 854 |         $DB->execute($sql);
 | 
        
           |  |  | 855 |   | 
        
           |  |  | 856 |         stats_progress('2');
 | 
        
           |  |  | 857 |   | 
        
           |  |  | 858 |     /// now enrolments averages
 | 
        
           |  |  | 859 |         $sql = "INSERT INTO {stats_monthly} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 860 |   | 
        
           |  |  | 861 |                 SELECT 'enrolments', ntimeend, courseid, roleid, " . $DB->sql_ceil('AVG(stat1)') . ", " . $DB->sql_ceil('AVG(stat2)') . "
 | 
        
           |  |  | 862 |                   FROM (
 | 
        
           |  |  | 863 |                            SELECT $nextstartmonth AS ntimeend, courseid, roleid, stat1, stat2
 | 
        
           |  |  | 864 |                              FROM {stats_daily} sd
 | 
        
           |  |  | 865 |                             WHERE stattype = 'enrolments' AND $stattimesql
 | 
        
           |  |  | 866 |                        ) inline_view
 | 
        
           |  |  | 867 |               GROUP BY ntimeend, courseid, roleid";
 | 
        
           |  |  | 868 |   | 
        
           |  |  | 869 |         $DB->execute($sql);
 | 
        
           |  |  | 870 |   | 
        
           |  |  | 871 |         stats_progress('3');
 | 
        
           |  |  | 872 |   | 
        
           |  |  | 873 |     /// activity read/write averages
 | 
        
           |  |  | 874 |         $sql = "INSERT INTO {stats_monthly} (stattype, timeend, courseid, roleid, stat1, stat2)
 | 
        
           |  |  | 875 |   | 
        
           |  |  | 876 |                 SELECT 'activity', ntimeend, courseid, roleid, SUM(stat1), SUM(stat2)
 | 
        
           |  |  | 877 |                   FROM (
 | 
        
           |  |  | 878 |                            SELECT $nextstartmonth AS ntimeend, courseid, roleid, stat1, stat2
 | 
        
           |  |  | 879 |                              FROM {stats_daily}
 | 
        
           |  |  | 880 |                             WHERE stattype = 'activity' AND $stattimesql
 | 
        
           |  |  | 881 |                        ) inline_view
 | 
        
           |  |  | 882 |               GROUP BY ntimeend, courseid, roleid";
 | 
        
           |  |  | 883 |   | 
        
           |  |  | 884 |         $DB->execute($sql);
 | 
        
           |  |  | 885 |   | 
        
           |  |  | 886 |         stats_progress('4');
 | 
        
           |  |  | 887 |   | 
        
           |  |  | 888 |     /// user read/write averages
 | 
        
           |  |  | 889 |         $sql = "INSERT INTO {stats_user_monthly} (stattype, timeend, courseid, userid, statsreads, statswrites)
 | 
        
           |  |  | 890 |   | 
        
           |  |  | 891 |                 SELECT 'activity', ntimeend, courseid, userid, SUM(statsreads), SUM(statswrites)
 | 
        
           |  |  | 892 |                   FROM (
 | 
        
           |  |  | 893 |                            SELECT $nextstartmonth AS ntimeend, courseid, userid, statsreads, statswrites
 | 
        
           |  |  | 894 |                              FROM {stats_user_daily}
 | 
        
           |  |  | 895 |                             WHERE stattype = 'activity' AND $stattimesql
 | 
        
           |  |  | 896 |                        ) inline_view
 | 
        
           |  |  | 897 |               GROUP BY ntimeend, courseid, userid";
 | 
        
           |  |  | 898 |   | 
        
           |  |  | 899 |         $DB->execute($sql);
 | 
        
           |  |  | 900 |   | 
        
           |  |  | 901 |         stats_progress('5');
 | 
        
           |  |  | 902 |   | 
        
           |  |  | 903 |         set_config('statslastmonthly', $nextstartmonth);
 | 
        
           |  |  | 904 |         $elapsed = time() - $monthstart;
 | 
        
           |  |  | 905 |         mtrace(" finished until $nextstartmonth: ".userdate($nextstartmonth) ." (in $elapsed s)");
 | 
        
           |  |  | 906 |   | 
        
           |  |  | 907 |         $timestart      = $nextstartmonth;
 | 
        
           |  |  | 908 |         $nextstartmonth = stats_get_next_month_start($nextstartmonth);
 | 
        
           |  |  | 909 |     }
 | 
        
           |  |  | 910 |   | 
        
           |  |  | 911 |     set_cron_lock('statsrunning', null);
 | 
        
           |  |  | 912 |     mtrace("...completed $months months of statistics.");
 | 
        
           |  |  | 913 |     return true;
 | 
        
           |  |  | 914 | }
 | 
        
           |  |  | 915 |   | 
        
           |  |  | 916 | /**
 | 
        
           |  |  | 917 |  * Return starting date of stats processing
 | 
        
           |  |  | 918 |  * @param string $str name of table - daily, weekly or monthly
 | 
        
           |  |  | 919 |  * @return int timestamp
 | 
        
           |  |  | 920 |  */
 | 
        
           |  |  | 921 | function stats_get_start_from($str) {
 | 
        
           |  |  | 922 |     global $CFG, $DB;
 | 
        
           |  |  | 923 |   | 
        
           |  |  | 924 |     // are there any data in stats table? Should not be...
 | 
        
           |  |  | 925 |     if ($timeend = $DB->get_field_sql('SELECT MAX(timeend) FROM {stats_'.$str.'}')) {
 | 
        
           |  |  | 926 |         return $timeend;
 | 
        
           |  |  | 927 |     }
 | 
        
           |  |  | 928 |     // decide what to do based on our config setting (either all or none or a timestamp)
 | 
        
           |  |  | 929 |     switch ($CFG->statsfirstrun) {
 | 
        
           |  |  | 930 |         case 'all':
 | 
        
           |  |  | 931 |             $manager = get_log_manager();
 | 
        
           |  |  | 932 |             $stores = $manager->get_readers();
 | 
        
           |  |  | 933 |             $firstlog = false;
 | 
        
           |  |  | 934 |             foreach ($stores as $store) {
 | 
        
           |  |  | 935 |                 if ($store instanceof \core\log\sql_internal_table_reader) {
 | 
        
           |  |  | 936 |                     $logtable = $store->get_internal_log_table_name();
 | 
        
           |  |  | 937 |                     if (!$logtable) {
 | 
        
           |  |  | 938 |                         continue;
 | 
        
           |  |  | 939 |                     }
 | 
        
           |  |  | 940 |                     $first = $DB->get_field_sql("SELECT MIN(timecreated) FROM {{$logtable}}");
 | 
        
           |  |  | 941 |                     if ($first and (!$firstlog or $firstlog > $first)) {
 | 
        
           |  |  | 942 |                         $firstlog = $first;
 | 
        
           |  |  | 943 |                     }
 | 
        
           |  |  | 944 |                 }
 | 
        
           |  |  | 945 |             }
 | 
        
           |  |  | 946 |   | 
        
           |  |  | 947 |             $first = $DB->get_field_sql('SELECT MIN(time) FROM {log}');
 | 
        
           |  |  | 948 |             if ($first and (!$firstlog or $firstlog > $first)) {
 | 
        
           |  |  | 949 |                 $firstlog = $first;
 | 
        
           |  |  | 950 |             }
 | 
        
           |  |  | 951 |   | 
        
           |  |  | 952 |             if ($firstlog) {
 | 
        
           |  |  | 953 |                 return $firstlog;
 | 
        
           |  |  | 954 |             }
 | 
        
           |  |  | 955 |   | 
        
           |  |  | 956 |         default:
 | 
        
           |  |  | 957 |             if (is_numeric($CFG->statsfirstrun)) {
 | 
        
           |  |  | 958 |                 return time() - $CFG->statsfirstrun;
 | 
        
           |  |  | 959 |             }
 | 
        
           |  |  | 960 |             // not a number? use next instead
 | 
        
           |  |  | 961 |         case 'none':
 | 
        
           |  |  | 962 |             return strtotime('-3 day', time());
 | 
        
           |  |  | 963 |     }
 | 
        
           |  |  | 964 | }
 | 
        
           |  |  | 965 |   | 
        
           |  |  | 966 | /**
 | 
        
           |  |  | 967 |  * Start of day
 | 
        
           |  |  | 968 |  * @param int $time timestamp
 | 
        
           |  |  | 969 |  * @return int start of day
 | 
        
           |  |  | 970 |  */
 | 
        
           |  |  | 971 | function stats_get_base_daily($time=0) {
 | 
        
           |  |  | 972 |     if (empty($time)) {
 | 
        
           |  |  | 973 |         $time = time();
 | 
        
           |  |  | 974 |     }
 | 
        
           |  |  | 975 |   | 
        
           |  |  | 976 |     core_date::set_default_server_timezone();
 | 
        
           |  |  | 977 |     $time = strtotime(date('d-M-Y', $time));
 | 
        
           |  |  | 978 |   | 
        
           |  |  | 979 |     return $time;
 | 
        
           |  |  | 980 | }
 | 
        
           |  |  | 981 |   | 
        
           |  |  | 982 | /**
 | 
        
           |  |  | 983 |  * Start of week
 | 
        
           |  |  | 984 |  * @param int $time timestamp
 | 
        
           |  |  | 985 |  * @return int start of week
 | 
        
           |  |  | 986 |  */
 | 
        
           |  |  | 987 | function stats_get_base_weekly($time=0) {
 | 
        
           |  |  | 988 |     global $CFG;
 | 
        
           |  |  | 989 |   | 
        
           |  |  | 990 |     $datetime = new DateTime();
 | 
        
           |  |  | 991 |     $datetime->setTimestamp(stats_get_base_daily($time));
 | 
        
           |  |  | 992 |     $startday = $CFG->calendar_startwday;
 | 
        
           |  |  | 993 |   | 
        
           |  |  | 994 |     core_date::set_default_server_timezone();
 | 
        
           |  |  | 995 |     $thisday = date('w', $time);
 | 
        
           |  |  | 996 |   | 
        
           |  |  | 997 |     $days = 0;
 | 
        
           |  |  | 998 |   | 
        
           |  |  | 999 |     if ($thisday > $startday) {
 | 
        
           |  |  | 1000 |         $days = $thisday - $startday;
 | 
        
           |  |  | 1001 |     } else if ($thisday < $startday) {
 | 
        
           |  |  | 1002 |         $days = 7 + $thisday - $startday;
 | 
        
           |  |  | 1003 |     }
 | 
        
           |  |  | 1004 |   | 
        
           |  |  | 1005 |     $datetime->sub(new DateInterval("P{$days}D"));
 | 
        
           |  |  | 1006 |   | 
        
           |  |  | 1007 |     return $datetime->getTimestamp();
 | 
        
           |  |  | 1008 | }
 | 
        
           |  |  | 1009 |   | 
        
           |  |  | 1010 | /**
 | 
        
           |  |  | 1011 |  * Start of month
 | 
        
           |  |  | 1012 |  * @param int $time timestamp
 | 
        
           |  |  | 1013 |  * @return int start of month
 | 
        
           |  |  | 1014 |  */
 | 
        
           |  |  | 1015 | function stats_get_base_monthly($time=0) {
 | 
        
           |  |  | 1016 |     if (empty($time)) {
 | 
        
           |  |  | 1017 |         $time = time();
 | 
        
           |  |  | 1018 |     }
 | 
        
           |  |  | 1019 |   | 
        
           |  |  | 1020 |     core_date::set_default_server_timezone();
 | 
        
           |  |  | 1021 |     $return = strtotime(date('1-M-Y', $time));
 | 
        
           |  |  | 1022 |   | 
        
           |  |  | 1023 |     return $return;
 | 
        
           |  |  | 1024 | }
 | 
        
           |  |  | 1025 |   | 
        
           |  |  | 1026 | /**
 | 
        
           |  |  | 1027 |  * Start of next day
 | 
        
           |  |  | 1028 |  * @param int $time timestamp
 | 
        
           |  |  | 1029 |  * @return int start of next day
 | 
        
           |  |  | 1030 |  */
 | 
        
           |  |  | 1031 | function stats_get_next_day_start($time) {
 | 
        
           |  |  | 1032 |     $next = stats_get_base_daily($time);
 | 
        
           |  |  | 1033 |     $nextdate = new DateTime();
 | 
        
           |  |  | 1034 |     $nextdate->setTimestamp($next);
 | 
        
           |  |  | 1035 |     $nextdate->add(new DateInterval('P1D'));
 | 
        
           |  |  | 1036 |     return $nextdate->getTimestamp();
 | 
        
           |  |  | 1037 | }
 | 
        
           |  |  | 1038 |   | 
        
           |  |  | 1039 | /**
 | 
        
           |  |  | 1040 |  * Start of next week
 | 
        
           |  |  | 1041 |  * @param int $time timestamp
 | 
        
           |  |  | 1042 |  * @return int start of next week
 | 
        
           |  |  | 1043 |  */
 | 
        
           |  |  | 1044 | function stats_get_next_week_start($time) {
 | 
        
           |  |  | 1045 |     $next = stats_get_base_weekly($time);
 | 
        
           |  |  | 1046 |     $nextdate = new DateTime();
 | 
        
           |  |  | 1047 |     $nextdate->setTimestamp($next);
 | 
        
           |  |  | 1048 |     $nextdate->add(new DateInterval('P1W'));
 | 
        
           |  |  | 1049 |     return $nextdate->getTimestamp();
 | 
        
           |  |  | 1050 | }
 | 
        
           |  |  | 1051 |   | 
        
           |  |  | 1052 | /**
 | 
        
           |  |  | 1053 |  * Start of next month
 | 
        
           |  |  | 1054 |  * @param int $time timestamp
 | 
        
           |  |  | 1055 |  * @return int start of next month
 | 
        
           |  |  | 1056 |  */
 | 
        
           |  |  | 1057 | function stats_get_next_month_start($time) {
 | 
        
           |  |  | 1058 |     $next = stats_get_base_monthly($time);
 | 
        
           |  |  | 1059 |     $nextdate = new DateTime();
 | 
        
           |  |  | 1060 |     $nextdate->setTimestamp($next);
 | 
        
           |  |  | 1061 |     $nextdate->add(new DateInterval('P1M'));
 | 
        
           |  |  | 1062 |     return $nextdate->getTimestamp();
 | 
        
           |  |  | 1063 | }
 | 
        
           |  |  | 1064 |   | 
        
           |  |  | 1065 | /**
 | 
        
           |  |  | 1066 |  * Remove old stats data
 | 
        
           |  |  | 1067 |  */
 | 
        
           |  |  | 1068 | function stats_clean_old() {
 | 
        
           |  |  | 1069 |     global $DB;
 | 
        
           |  |  | 1070 |     mtrace("Running stats cleanup tasks...");
 | 
        
           |  |  | 1071 |     \core\cron::trace_time_and_memory();
 | 
        
           |  |  | 1072 |     $deletebefore =  stats_get_base_monthly();
 | 
        
           |  |  | 1073 |   | 
        
           |  |  | 1074 |     // delete dailies older than 3 months (to be safe)
 | 
        
           |  |  | 1075 |     $deletebefore = strtotime('-3 months', $deletebefore);
 | 
        
           |  |  | 1076 |     $DB->delete_records_select('stats_daily',      "timeend < $deletebefore");
 | 
        
           |  |  | 1077 |     $DB->delete_records_select('stats_user_daily', "timeend < $deletebefore");
 | 
        
           |  |  | 1078 |   | 
        
           |  |  | 1079 |     // delete weeklies older than 9  months (to be safe)
 | 
        
           |  |  | 1080 |     $deletebefore = strtotime('-6 months', $deletebefore);
 | 
        
           |  |  | 1081 |     $DB->delete_records_select('stats_weekly',      "timeend < $deletebefore");
 | 
        
           |  |  | 1082 |     $DB->delete_records_select('stats_user_weekly', "timeend < $deletebefore");
 | 
        
           |  |  | 1083 |   | 
        
           |  |  | 1084 |     // don't delete monthlies
 | 
        
           |  |  | 1085 |   | 
        
           |  |  | 1086 |     mtrace("...stats cleanup finished");
 | 
        
           |  |  | 1087 | }
 | 
        
           |  |  | 1088 |   | 
        
           |  |  | 1089 | function stats_get_parameters($time,$report,$courseid,$mode,$roleid=0) {
 | 
        
           |  |  | 1090 |     global $CFG, $DB;
 | 
        
           |  |  | 1091 |   | 
        
           |  |  | 1092 |     $param = new stdClass();
 | 
        
           |  |  | 1093 |     $param->params = array();
 | 
        
           |  |  | 1094 |   | 
        
           |  |  | 1095 |     if ($time < 10) { // dailies
 | 
        
           |  |  | 1096 |         // number of days to go back = 7* time
 | 
        
           |  |  | 1097 |         $param->table = 'daily';
 | 
        
           |  |  | 1098 |         $param->timeafter = strtotime("-".($time*7)." days",stats_get_base_daily());
 | 
        
           |  |  | 1099 |     } elseif ($time < 20) { // weeklies
 | 
        
           |  |  | 1100 |         // number of weeks to go back = time - 10 * 4 (weeks) + base week
 | 
        
           |  |  | 1101 |         $param->table = 'weekly';
 | 
        
           |  |  | 1102 |         $param->timeafter = strtotime("-".(($time - 10)*4)." weeks",stats_get_base_weekly());
 | 
        
           |  |  | 1103 |     } else { // monthlies.
 | 
        
           |  |  | 1104 |         // number of months to go back = time - 20 * months + base month
 | 
        
           |  |  | 1105 |         $param->table = 'monthly';
 | 
        
           |  |  | 1106 |         $param->timeafter = strtotime("-".($time - 20)." months",stats_get_base_monthly());
 | 
        
           |  |  | 1107 |     }
 | 
        
           |  |  | 1108 |   | 
        
           |  |  | 1109 |     $param->extras = '';
 | 
        
           |  |  | 1110 |   | 
        
           |  |  | 1111 |     switch ($report) {
 | 
        
           |  |  | 1112 |     // ******************** STATS_MODE_GENERAL ******************** //
 | 
        
           |  |  | 1113 |     case STATS_REPORT_LOGINS:
 | 
        
           |  |  | 1114 |         $param->fields = 'timeend,sum(stat1) as line1,sum(stat2) as line2';
 | 
        
           |  |  | 1115 |         $param->fieldscomplete = true;
 | 
        
           |  |  | 1116 |         $param->stattype = 'logins';
 | 
        
           |  |  | 1117 |         $param->line1 = get_string('statslogins');
 | 
        
           |  |  | 1118 |         $param->line2 = get_string('statsuniquelogins');
 | 
        
           |  |  | 1119 |         if ($courseid == SITEID) {
 | 
        
           |  |  | 1120 |             $param->extras = 'GROUP BY timeend';
 | 
        
           |  |  | 1121 |         }
 | 
        
           |  |  | 1122 |         break;
 | 
        
           |  |  | 1123 |   | 
        
           |  |  | 1124 |     case STATS_REPORT_READS:
 | 
        
           |  |  | 1125 |         $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, stat1 as line1';
 | 
        
           |  |  | 1126 |         $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries.
 | 
        
           |  |  | 1127 |         $param->aggregategroupby = 'roleid';
 | 
        
           |  |  | 1128 |         $param->stattype = 'activity';
 | 
        
           |  |  | 1129 |         $param->crosstab = true;
 | 
        
           |  |  | 1130 |         $param->extras = 'GROUP BY timeend,roleid,stat1';
 | 
        
           |  |  | 1131 |         if ($courseid == SITEID) {
 | 
        
           |  |  | 1132 |             $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, sum(stat1) as line1';
 | 
        
           |  |  | 1133 |             $param->extras = 'GROUP BY timeend,roleid';
 | 
        
           |  |  | 1134 |         }
 | 
        
           |  |  | 1135 |         break;
 | 
        
           |  |  | 1136 |   | 
        
           |  |  | 1137 |     case STATS_REPORT_WRITES:
 | 
        
           |  |  | 1138 |         $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, stat2 as line1';
 | 
        
           |  |  | 1139 |         $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries.
 | 
        
           |  |  | 1140 |         $param->aggregategroupby = 'roleid';
 | 
        
           |  |  | 1141 |         $param->stattype = 'activity';
 | 
        
           |  |  | 1142 |         $param->crosstab = true;
 | 
        
           |  |  | 1143 |         $param->extras = 'GROUP BY timeend,roleid,stat2';
 | 
        
           |  |  | 1144 |         if ($courseid == SITEID) {
 | 
        
           |  |  | 1145 |             $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, sum(stat2) as line1';
 | 
        
           |  |  | 1146 |             $param->extras = 'GROUP BY timeend,roleid';
 | 
        
           |  |  | 1147 |         }
 | 
        
           |  |  | 1148 |         break;
 | 
        
           |  |  | 1149 |   | 
        
           |  |  | 1150 |     case STATS_REPORT_ACTIVITY:
 | 
        
           |  |  | 1151 |         $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, sum(stat1+stat2) as line1';
 | 
        
           |  |  | 1152 |         $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries.
 | 
        
           |  |  | 1153 |         $param->aggregategroupby = 'roleid';
 | 
        
           |  |  | 1154 |         $param->stattype = 'activity';
 | 
        
           |  |  | 1155 |         $param->crosstab = true;
 | 
        
           |  |  | 1156 |         $param->extras = 'GROUP BY timeend,roleid';
 | 
        
           |  |  | 1157 |         if ($courseid == SITEID) {
 | 
        
           |  |  | 1158 |             $param->extras = 'GROUP BY timeend,roleid';
 | 
        
           |  |  | 1159 |         }
 | 
        
           |  |  | 1160 |         break;
 | 
        
           |  |  | 1161 |   | 
        
           |  |  | 1162 |     case STATS_REPORT_ACTIVITYBYROLE;
 | 
        
           |  |  | 1163 |         $param->fields = 'stat1 AS line1, stat2 AS line2';
 | 
        
           |  |  | 1164 |         $param->stattype = 'activity';
 | 
        
           |  |  | 1165 |         $rolename = '';
 | 
        
           |  |  | 1166 |         if ($roleid <> 0) {
 | 
        
           |  |  | 1167 |             if ($role = $DB->get_record('role', ['id' => $roleid])) {
 | 
        
           |  |  | 1168 |                 $rolename = role_get_name($role, context_course::instance($courseid)) . ' ';
 | 
        
           |  |  | 1169 |             }
 | 
        
           |  |  | 1170 |         }
 | 
        
           |  |  | 1171 |         $param->line1 = $rolename . get_string('statsreads');
 | 
        
           |  |  | 1172 |         $param->line2 = $rolename . get_string('statswrites');
 | 
        
           |  |  | 1173 |         if ($courseid == SITEID) {
 | 
        
           |  |  | 1174 |             $param->extras = 'GROUP BY timeend';
 | 
        
           |  |  | 1175 |         }
 | 
        
           |  |  | 1176 |         break;
 | 
        
           |  |  | 1177 |   | 
        
           |  |  | 1178 |     // ******************** STATS_MODE_DETAILED ******************** //
 | 
        
           |  |  | 1179 |     case STATS_REPORT_USER_ACTIVITY:
 | 
        
           |  |  | 1180 |         $param->fields = 'statsreads as line1, statswrites as line2';
 | 
        
           |  |  | 1181 |         $param->line1 = get_string('statsuserreads');
 | 
        
           |  |  | 1182 |         $param->line2 = get_string('statsuserwrites');
 | 
        
           |  |  | 1183 |         $param->stattype = 'activity';
 | 
        
           |  |  | 1184 |         break;
 | 
        
           |  |  | 1185 |   | 
        
           |  |  | 1186 |     case STATS_REPORT_USER_ALLACTIVITY:
 | 
        
           |  |  | 1187 |         $param->fields = 'statsreads+statswrites as line1';
 | 
        
           |  |  | 1188 |         $param->line1 = get_string('statsuseractivity');
 | 
        
           |  |  | 1189 |         $param->stattype = 'activity';
 | 
        
           |  |  | 1190 |         break;
 | 
        
           |  |  | 1191 |   | 
        
           |  |  | 1192 |     case STATS_REPORT_USER_LOGINS:
 | 
        
           |  |  | 1193 |         $param->fields = 'statsreads as line1';
 | 
        
           |  |  | 1194 |         $param->line1 = get_string('statsuserlogins');
 | 
        
           |  |  | 1195 |         $param->stattype = 'logins';
 | 
        
           |  |  | 1196 |         break;
 | 
        
           |  |  | 1197 |   | 
        
           |  |  | 1198 |     case STATS_REPORT_USER_VIEW:
 | 
        
           |  |  | 1199 |         $param->fields = 'timeend, SUM(statsreads) AS line1, SUM(statswrites) AS line2, SUM(statsreads+statswrites) AS line3';
 | 
        
           |  |  | 1200 |         $param->fieldscomplete = true;
 | 
        
           |  |  | 1201 |         $param->line1 = get_string('statsuserreads');
 | 
        
           |  |  | 1202 |         $param->line2 = get_string('statsuserwrites');
 | 
        
           |  |  | 1203 |         $param->line3 = get_string('statsuseractivity');
 | 
        
           |  |  | 1204 |         $param->stattype = 'activity';
 | 
        
           |  |  | 1205 |         $param->extras = "GROUP BY timeend";
 | 
        
           |  |  | 1206 |         break;
 | 
        
           |  |  | 1207 |   | 
        
           |  |  | 1208 |     // ******************** STATS_MODE_RANKED ******************** //
 | 
        
           |  |  | 1209 |     case STATS_REPORT_ACTIVE_COURSES:
 | 
        
           |  |  | 1210 |         $param->fields = 'sum(stat1+stat2) AS line1';
 | 
        
           |  |  | 1211 |         $param->stattype = 'activity';
 | 
        
           |  |  | 1212 |         $param->orderby = 'line1 DESC';
 | 
        
           |  |  | 1213 |         $param->line1 = get_string('useractivity');
 | 
        
           |  |  | 1214 |         $param->graphline = 'line1';
 | 
        
           |  |  | 1215 |         break;
 | 
        
           |  |  | 1216 |   | 
        
           |  |  | 1217 |     case STATS_REPORT_ACTIVE_COURSES_WEIGHTED:
 | 
        
           |  |  | 1218 |         $threshold = 0;
 | 
        
           |  |  | 1219 |         if (!empty($CFG->statsuserthreshold) && is_numeric($CFG->statsuserthreshold)) {
 | 
        
           |  |  | 1220 |             $threshold = $CFG->statsuserthreshold;
 | 
        
           |  |  | 1221 |         }
 | 
        
           |  |  | 1222 |         $param->fields = '';
 | 
        
           |  |  | 1223 |         $param->sql = 'SELECT activity.courseid, activity.all_activity AS line1, enrolments.highest_enrolments AS line2,
 | 
        
           |  |  | 1224 |                         activity.all_activity / enrolments.highest_enrolments as line3
 | 
        
           |  |  | 1225 |                        FROM (
 | 
        
           |  |  | 1226 |                             SELECT courseid, sum(stat1+stat2) AS all_activity
 | 
        
           |  |  | 1227 |                               FROM {stats_'.$param->table.'}
 | 
        
           |  |  | 1228 |                              WHERE stattype=\'activity\' AND timeend >= '.(int)$param->timeafter.' AND roleid = 0 GROUP BY courseid
 | 
        
           |  |  | 1229 |                        ) activity
 | 
        
           |  |  | 1230 |                        INNER JOIN
 | 
        
           |  |  | 1231 |                             (
 | 
        
           |  |  | 1232 |                             SELECT courseid, max(stat1) AS highest_enrolments
 | 
        
           |  |  | 1233 |                               FROM {stats_'.$param->table.'}
 | 
        
           |  |  | 1234 |                              WHERE stattype=\'enrolments\' AND timeend >= '.(int)$param->timeafter.' AND stat1 > '.(int)$threshold.'
 | 
        
           |  |  | 1235 |                           GROUP BY courseid
 | 
        
           |  |  | 1236 |                       ) enrolments
 | 
        
           |  |  | 1237 |                       ON (activity.courseid = enrolments.courseid)
 | 
        
           |  |  | 1238 |                       ORDER BY line3 DESC';
 | 
        
           |  |  | 1239 |         $param->line1 = get_string('useractivity');
 | 
        
           |  |  | 1240 |         $param->line2 = get_string('users');
 | 
        
           |  |  | 1241 |         $param->line3 = get_string('activityweighted');
 | 
        
           |  |  | 1242 |         $param->graphline = 'line3';
 | 
        
           |  |  | 1243 |         break;
 | 
        
           |  |  | 1244 |   | 
        
           |  |  | 1245 |     case STATS_REPORT_PARTICIPATORY_COURSES:
 | 
        
           |  |  | 1246 |         $threshold = 0;
 | 
        
           |  |  | 1247 |         if (!empty($CFG->statsuserthreshold) && is_numeric($CFG->statsuserthreshold)) {
 | 
        
           |  |  | 1248 |             $threshold = $CFG->statsuserthreshold;
 | 
        
           |  |  | 1249 |         }
 | 
        
           |  |  | 1250 |         $param->fields = '';
 | 
        
           |  |  | 1251 |         $param->sql = 'SELECT courseid, ' . $DB->sql_ceil('avg(all_enrolments)') . ' as line1, ' .
 | 
        
           |  |  | 1252 |                          $DB->sql_ceil('avg(active_enrolments)') . ' as line2, avg(proportion_active) AS line3
 | 
        
           |  |  | 1253 |                        FROM (
 | 
        
           |  |  | 1254 |                            SELECT courseid, timeend, stat2 as active_enrolments,
 | 
        
           |  |  | 1255 |                                   stat1 as all_enrolments, '.$DB->sql_cast_char2real('stat2').'/'.$DB->sql_cast_char2real('stat1').' AS proportion_active
 | 
        
           |  |  | 1256 |                              FROM {stats_'.$param->table.'}
 | 
        
           |  |  | 1257 |                             WHERE stattype=\'enrolments\' AND roleid = 0 AND stat1 > '.(int)$threshold.'
 | 
        
           |  |  | 1258 |                        ) aq
 | 
        
           |  |  | 1259 |                        WHERE timeend >= '.(int)$param->timeafter.'
 | 
        
           |  |  | 1260 |                        GROUP BY courseid
 | 
        
           |  |  | 1261 |                        ORDER BY line3 DESC';
 | 
        
           |  |  | 1262 |   | 
        
           |  |  | 1263 |         $param->line1 = get_string('users');
 | 
        
           |  |  | 1264 |         $param->line2 = get_string('activeusers');
 | 
        
           |  |  | 1265 |         $param->line3 = get_string('participationratio');
 | 
        
           |  |  | 1266 |         $param->graphline = 'line3';
 | 
        
           |  |  | 1267 |         break;
 | 
        
           |  |  | 1268 |   | 
        
           |  |  | 1269 |     case STATS_REPORT_PARTICIPATORY_COURSES_RW:
 | 
        
           |  |  | 1270 |         $param->fields = '';
 | 
        
           |  |  | 1271 |         $param->sql =  'SELECT courseid, sum(views) AS line1, sum(posts) AS line2,
 | 
        
           |  |  | 1272 |                            avg(proportion_active) AS line3
 | 
        
           |  |  | 1273 |                          FROM (
 | 
        
           |  |  | 1274 |                            SELECT courseid, timeend, stat1 as views, stat2 AS posts,
 | 
        
           |  |  | 1275 |                                   '.$DB->sql_cast_char2real('stat2').'/'.$DB->sql_cast_char2real('stat1').' as proportion_active
 | 
        
           |  |  | 1276 |                              FROM {stats_'.$param->table.'}
 | 
        
           |  |  | 1277 |                             WHERE stattype=\'activity\' AND roleid = 0 AND stat1 > 0
 | 
        
           |  |  | 1278 |                        ) aq
 | 
        
           |  |  | 1279 |                        WHERE timeend >= '.(int)$param->timeafter.'
 | 
        
           |  |  | 1280 |                        GROUP BY courseid
 | 
        
           |  |  | 1281 |                        ORDER BY line3 DESC';
 | 
        
           |  |  | 1282 |         $param->line1 = get_string('views');
 | 
        
           |  |  | 1283 |         $param->line2 = get_string('posts');
 | 
        
           |  |  | 1284 |         $param->line3 = get_string('participationratio');
 | 
        
           |  |  | 1285 |         $param->graphline = 'line3';
 | 
        
           |  |  | 1286 |         break;
 | 
        
           |  |  | 1287 |     }
 | 
        
           |  |  | 1288 |   | 
        
           |  |  | 1289 |     /*
 | 
        
           |  |  | 1290 |     if ($courseid == SITEID && $mode != STATS_MODE_RANKED) { // just aggregate all courses.
 | 
        
           |  |  | 1291 |         $param->fields = preg_replace('/(?:sum)([a-zA-Z0-9+_]*)\W+as\W+([a-zA-Z0-9_]*)/i','sum($1) as $2',$param->fields);
 | 
        
           |  |  | 1292 |         $param->extras = ' GROUP BY timeend'.((!empty($param->aggregategroupby)) ? ','.$param->aggregategroupby : '');
 | 
        
           |  |  | 1293 |     }
 | 
        
           |  |  | 1294 |     */
 | 
        
           |  |  | 1295 |     //TODO must add the SITEID reports to the rest of the reports.
 | 
        
           |  |  | 1296 |     return $param;
 | 
        
           |  |  | 1297 | }
 | 
        
           |  |  | 1298 |   | 
        
           |  |  | 1299 | function stats_get_view_actions() {
 | 
        
           |  |  | 1300 |     return array('view','view all','history');
 | 
        
           |  |  | 1301 | }
 | 
        
           |  |  | 1302 |   | 
        
           |  |  | 1303 | function stats_get_post_actions() {
 | 
        
           | 1441 | ariadna | 1304 |     return ['add', 'delete', 'edit', 'add mod', 'delete mod', 'edit section', 'enrol', 'loginas', 'new', 'unenrol', 'update',
 | 
        
           |  |  | 1305 |             'update mod'];
 | 
        
           | 1 | efrain | 1306 | }
 | 
        
           |  |  | 1307 |   | 
        
           |  |  | 1308 | function stats_get_action_names($str) {
 | 
        
           |  |  | 1309 |     global $CFG, $DB;
 | 
        
           |  |  | 1310 |   | 
        
           |  |  | 1311 |     $mods = $DB->get_records('modules');
 | 
        
           |  |  | 1312 |     $function = 'stats_get_'.$str.'_actions';
 | 
        
           |  |  | 1313 |     $actions = $function();
 | 
        
           |  |  | 1314 |     foreach ($mods as $mod) {
 | 
        
           |  |  | 1315 |         $file = $CFG->dirroot.'/mod/'.$mod->name.'/lib.php';
 | 
        
           |  |  | 1316 |         if (!is_readable($file)) {
 | 
        
           |  |  | 1317 |             continue;
 | 
        
           |  |  | 1318 |         }
 | 
        
           |  |  | 1319 |         require_once($file);
 | 
        
           |  |  | 1320 |         $function = $mod->name.'_get_'.$str.'_actions';
 | 
        
           |  |  | 1321 |         if (function_exists($function)) {
 | 
        
           |  |  | 1322 |             $mod_actions = $function();
 | 
        
           |  |  | 1323 |             if (is_array($mod_actions)) {
 | 
        
           |  |  | 1324 |                 $actions = array_merge($actions, $mod_actions);
 | 
        
           |  |  | 1325 |             }
 | 
        
           |  |  | 1326 |         }
 | 
        
           |  |  | 1327 |     }
 | 
        
           |  |  | 1328 |   | 
        
           |  |  | 1329 |     // The array_values() forces a stack-like array
 | 
        
           |  |  | 1330 |     // so we can later loop over safely...
 | 
        
           |  |  | 1331 |     $actions =  array_values(array_unique($actions));
 | 
        
           |  |  | 1332 |     $c = count($actions);
 | 
        
           |  |  | 1333 |     for ($n=0;$n<$c;$n++) {
 | 
        
           |  |  | 1334 |         $actions[$n] = $actions[$n];
 | 
        
           |  |  | 1335 |     }
 | 
        
           |  |  | 1336 |     return $actions;
 | 
        
           |  |  | 1337 | }
 | 
        
           |  |  | 1338 |   | 
        
           |  |  | 1339 | function stats_get_time_options($now,$lastweekend,$lastmonthend,$earliestday,$earliestweek,$earliestmonth) {
 | 
        
           |  |  | 1340 |   | 
        
           |  |  | 1341 |     $now = stats_get_base_daily(time());
 | 
        
           |  |  | 1342 |     // it's really important that it's TIMEEND in the table. ie, tuesday 00:00:00 is monday night.
 | 
        
           |  |  | 1343 |     // so we need to take a day off here (essentially add a day to $now
 | 
        
           |  |  | 1344 |     $now += 60*60*24;
 | 
        
           |  |  | 1345 |   | 
        
           |  |  | 1346 |     $timeoptions = array();
 | 
        
           |  |  | 1347 |   | 
        
           |  |  | 1348 |     if ($now - (60*60*24*7) >= $earliestday) {
 | 
        
           |  |  | 1349 |         $timeoptions[STATS_TIME_LASTWEEK] = get_string('numweeks','moodle',1);
 | 
        
           |  |  | 1350 |     }
 | 
        
           |  |  | 1351 |     if ($now - (60*60*24*14) >= $earliestday) {
 | 
        
           |  |  | 1352 |         $timeoptions[STATS_TIME_LAST2WEEKS] = get_string('numweeks','moodle',2);
 | 
        
           |  |  | 1353 |     }
 | 
        
           |  |  | 1354 |     if ($now - (60*60*24*21) >= $earliestday) {
 | 
        
           |  |  | 1355 |         $timeoptions[STATS_TIME_LAST3WEEKS] = get_string('numweeks','moodle',3);
 | 
        
           |  |  | 1356 |     }
 | 
        
           |  |  | 1357 |     if ($now - (60*60*24*28) >= $earliestday) {
 | 
        
           |  |  | 1358 |         $timeoptions[STATS_TIME_LAST4WEEKS] = get_string('numweeks','moodle',4);// show dailies up to (including) here.
 | 
        
           |  |  | 1359 |     }
 | 
        
           |  |  | 1360 |     if ($lastweekend - (60*60*24*56) >= $earliestweek) {
 | 
        
           |  |  | 1361 |         $timeoptions[STATS_TIME_LAST2MONTHS] = get_string('nummonths','moodle',2);
 | 
        
           |  |  | 1362 |     }
 | 
        
           |  |  | 1363 |     if ($lastweekend - (60*60*24*84) >= $earliestweek) {
 | 
        
           |  |  | 1364 |         $timeoptions[STATS_TIME_LAST3MONTHS] = get_string('nummonths','moodle',3);
 | 
        
           |  |  | 1365 |     }
 | 
        
           |  |  | 1366 |     if ($lastweekend - (60*60*24*112) >= $earliestweek) {
 | 
        
           |  |  | 1367 |         $timeoptions[STATS_TIME_LAST4MONTHS] = get_string('nummonths','moodle',4);
 | 
        
           |  |  | 1368 |     }
 | 
        
           |  |  | 1369 |     if ($lastweekend - (60*60*24*140) >= $earliestweek) {
 | 
        
           |  |  | 1370 |         $timeoptions[STATS_TIME_LAST5MONTHS] = get_string('nummonths','moodle',5);
 | 
        
           |  |  | 1371 |     }
 | 
        
           |  |  | 1372 |     if ($lastweekend - (60*60*24*168) >= $earliestweek) {
 | 
        
           |  |  | 1373 |         $timeoptions[STATS_TIME_LAST6MONTHS] = get_string('nummonths','moodle',6); // show weeklies up to (including) here
 | 
        
           |  |  | 1374 |     }
 | 
        
           |  |  | 1375 |     if (strtotime('-7 months',$lastmonthend) >= $earliestmonth) {
 | 
        
           |  |  | 1376 |         $timeoptions[STATS_TIME_LAST7MONTHS] = get_string('nummonths','moodle',7);
 | 
        
           |  |  | 1377 |     }
 | 
        
           |  |  | 1378 |     if (strtotime('-8 months',$lastmonthend) >= $earliestmonth) {
 | 
        
           |  |  | 1379 |         $timeoptions[STATS_TIME_LAST8MONTHS] = get_string('nummonths','moodle',8);
 | 
        
           |  |  | 1380 |     }
 | 
        
           |  |  | 1381 |     if (strtotime('-9 months',$lastmonthend) >= $earliestmonth) {
 | 
        
           |  |  | 1382 |         $timeoptions[STATS_TIME_LAST9MONTHS] = get_string('nummonths','moodle',9);
 | 
        
           |  |  | 1383 |     }
 | 
        
           |  |  | 1384 |     if (strtotime('-10 months',$lastmonthend) >= $earliestmonth) {
 | 
        
           |  |  | 1385 |         $timeoptions[STATS_TIME_LAST10MONTHS] = get_string('nummonths','moodle',10);
 | 
        
           |  |  | 1386 |     }
 | 
        
           |  |  | 1387 |     if (strtotime('-11 months',$lastmonthend) >= $earliestmonth) {
 | 
        
           |  |  | 1388 |         $timeoptions[STATS_TIME_LAST11MONTHS] = get_string('nummonths','moodle',11);
 | 
        
           |  |  | 1389 |     }
 | 
        
           |  |  | 1390 |     if (strtotime('-1 year',$lastmonthend) >= $earliestmonth) {
 | 
        
           |  |  | 1391 |         $timeoptions[STATS_TIME_LASTYEAR] = get_string('lastyear');
 | 
        
           |  |  | 1392 |     }
 | 
        
           |  |  | 1393 |   | 
        
           |  |  | 1394 |     $years = (int)date('y', $now) - (int)date('y', $earliestmonth);
 | 
        
           |  |  | 1395 |     if ($years > 1) {
 | 
        
           |  |  | 1396 |         for($i = 2; $i <= $years; $i++) {
 | 
        
           |  |  | 1397 |             $timeoptions[$i*12+20] = get_string('numyears', 'moodle', $i);
 | 
        
           |  |  | 1398 |         }
 | 
        
           |  |  | 1399 |     }
 | 
        
           |  |  | 1400 |   | 
        
           |  |  | 1401 |     return $timeoptions;
 | 
        
           |  |  | 1402 | }
 | 
        
           |  |  | 1403 |   | 
        
           |  |  | 1404 | function stats_get_report_options($courseid,$mode) {
 | 
        
           |  |  | 1405 |     global $CFG, $DB;
 | 
        
           |  |  | 1406 |   | 
        
           |  |  | 1407 |     $reportoptions = array();
 | 
        
           |  |  | 1408 |   | 
        
           |  |  | 1409 |     switch ($mode) {
 | 
        
           |  |  | 1410 |     case STATS_MODE_GENERAL:
 | 
        
           |  |  | 1411 |         $reportoptions[STATS_REPORT_ACTIVITY] = get_string('statsreport'.STATS_REPORT_ACTIVITY);
 | 
        
           |  |  | 1412 |         if ($courseid != SITEID && $context = context_course::instance($courseid)) {
 | 
        
           |  |  | 1413 |             $sql = 'SELECT r.id, r.name, r.shortname FROM {role} r JOIN {stats_daily} s ON s.roleid = r.id
 | 
        
           |  |  | 1414 |                  WHERE s.courseid = :courseid GROUP BY r.id, r.name, r.shortname';
 | 
        
           |  |  | 1415 |             if ($roles = $DB->get_records_sql($sql, array('courseid' => $courseid))) {
 | 
        
           |  |  | 1416 |                 $roles = array_intersect_key($roles, get_viewable_roles($context));
 | 
        
           |  |  | 1417 |                 foreach ($roles as $role) {
 | 
        
           |  |  | 1418 |                     $reportoptions[STATS_REPORT_ACTIVITYBYROLE.$role->id] = get_string('statsreport'.STATS_REPORT_ACTIVITYBYROLE).
 | 
        
           |  |  | 1419 |                         ' ' . role_get_name($role, $context);
 | 
        
           |  |  | 1420 |                 }
 | 
        
           |  |  | 1421 |             }
 | 
        
           |  |  | 1422 |         }
 | 
        
           |  |  | 1423 |         $reportoptions[STATS_REPORT_READS] = get_string('statsreport'.STATS_REPORT_READS);
 | 
        
           |  |  | 1424 |         $reportoptions[STATS_REPORT_WRITES] = get_string('statsreport'.STATS_REPORT_WRITES);
 | 
        
           |  |  | 1425 |         if ($courseid == SITEID) {
 | 
        
           |  |  | 1426 |             $reportoptions[STATS_REPORT_LOGINS] = get_string('statsreport'.STATS_REPORT_LOGINS);
 | 
        
           |  |  | 1427 |         }
 | 
        
           |  |  | 1428 |   | 
        
           |  |  | 1429 |         break;
 | 
        
           |  |  | 1430 |     case STATS_MODE_DETAILED:
 | 
        
           |  |  | 1431 |         $reportoptions[STATS_REPORT_USER_ACTIVITY] = get_string('statsreport'.STATS_REPORT_USER_ACTIVITY);
 | 
        
           |  |  | 1432 |         $reportoptions[STATS_REPORT_USER_ALLACTIVITY] = get_string('statsreport'.STATS_REPORT_USER_ALLACTIVITY);
 | 
        
           |  |  | 1433 |         if (has_capability('report/stats:view', context_system::instance())) {
 | 
        
           |  |  | 1434 |             $site = get_site();
 | 
        
           |  |  | 1435 |             $reportoptions[STATS_REPORT_USER_LOGINS] = get_string('statsreport'.STATS_REPORT_USER_LOGINS);
 | 
        
           |  |  | 1436 |         }
 | 
        
           |  |  | 1437 |         break;
 | 
        
           |  |  | 1438 |     case STATS_MODE_RANKED:
 | 
        
           |  |  | 1439 |         if (has_capability('report/stats:view', context_system::instance())) {
 | 
        
           |  |  | 1440 |             $reportoptions[STATS_REPORT_ACTIVE_COURSES] = get_string('statsreport'.STATS_REPORT_ACTIVE_COURSES);
 | 
        
           |  |  | 1441 |             $reportoptions[STATS_REPORT_ACTIVE_COURSES_WEIGHTED] = get_string('statsreport'.STATS_REPORT_ACTIVE_COURSES_WEIGHTED);
 | 
        
           |  |  | 1442 |             $reportoptions[STATS_REPORT_PARTICIPATORY_COURSES] = get_string('statsreport'.STATS_REPORT_PARTICIPATORY_COURSES);
 | 
        
           |  |  | 1443 |             $reportoptions[STATS_REPORT_PARTICIPATORY_COURSES_RW] = get_string('statsreport'.STATS_REPORT_PARTICIPATORY_COURSES_RW);
 | 
        
           |  |  | 1444 |         }
 | 
        
           |  |  | 1445 |         break;
 | 
        
           |  |  | 1446 |     }
 | 
        
           |  |  | 1447 |   | 
        
           |  |  | 1448 |     return $reportoptions;
 | 
        
           |  |  | 1449 | }
 | 
        
           |  |  | 1450 |   | 
        
           |  |  | 1451 | /**
 | 
        
           |  |  | 1452 |  * Fix missing entries in the statistics.
 | 
        
           |  |  | 1453 |  *
 | 
        
           |  |  | 1454 |  * This creates a dummy stat when nothing happened during a day/week/month.
 | 
        
           |  |  | 1455 |  *
 | 
        
           |  |  | 1456 |  * @param array $stats array of statistics.
 | 
        
           |  |  | 1457 |  * @param int $timeafter unused.
 | 
        
           |  |  | 1458 |  * @param string $timestr type of statistics to generate (dayly, weekly, monthly).
 | 
        
           |  |  | 1459 |  * @param boolean $line2
 | 
        
           |  |  | 1460 |  * @param boolean $line3
 | 
        
           |  |  | 1461 |  * @return ?array of fixed statistics.
 | 
        
           |  |  | 1462 |  */
 | 
        
           |  |  | 1463 | function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) {
 | 
        
           |  |  | 1464 |   | 
        
           |  |  | 1465 |     if (empty($stats)) {
 | 
        
           |  |  | 1466 |         return;
 | 
        
           |  |  | 1467 |     }
 | 
        
           |  |  | 1468 |   | 
        
           |  |  | 1469 |     $timestr = str_replace('user_','',$timestr); // just in case.
 | 
        
           |  |  | 1470 |   | 
        
           |  |  | 1471 |     // Gets the current user base time.
 | 
        
           |  |  | 1472 |     $fun = 'stats_get_base_'.$timestr;
 | 
        
           |  |  | 1473 |     $now = $fun();
 | 
        
           |  |  | 1474 |   | 
        
           |  |  | 1475 |     // Extract the ending time of the statistics.
 | 
        
           |  |  | 1476 |     $actualtimes = array();
 | 
        
           |  |  | 1477 |     $actualtimeshour = null;
 | 
        
           |  |  | 1478 |     foreach ($stats as $statid => $s) {
 | 
        
           |  |  | 1479 |         // Normalise the month date to the 1st if for any reason it's set to later. But we ignore
 | 
        
           |  |  | 1480 |         // anything above or equal to 29 because sometimes we get the end of the month. Also, we will
 | 
        
           |  |  | 1481 |         // set the hours of the result to all of them, that way we prevent DST differences.
 | 
        
           |  |  | 1482 |         if ($timestr == 'monthly') {
 | 
        
           |  |  | 1483 |             $day = date('d', $s->timeend);
 | 
        
           |  |  | 1484 |             if (date('d', $s->timeend) > 1 && date('d', $s->timeend) < 29) {
 | 
        
           |  |  | 1485 |                 $day = 1;
 | 
        
           |  |  | 1486 |             }
 | 
        
           |  |  | 1487 |             if (is_null($actualtimeshour)) {
 | 
        
           |  |  | 1488 |                 $actualtimeshour = date('H', $s->timeend);
 | 
        
           |  |  | 1489 |             }
 | 
        
           |  |  | 1490 |             $s->timeend = mktime($actualtimeshour, 0, 0, date('m', $s->timeend), $day, date('Y', $s->timeend));
 | 
        
           |  |  | 1491 |         }
 | 
        
           |  |  | 1492 |         $stats[$statid] = $s;
 | 
        
           |  |  | 1493 |         $actualtimes[] = $s->timeend;
 | 
        
           |  |  | 1494 |     }
 | 
        
           |  |  | 1495 |   | 
        
           |  |  | 1496 |     $actualtimesvalues = array_values($actualtimes);
 | 
        
           |  |  | 1497 |     $timeafter = array_pop($actualtimesvalues);
 | 
        
           |  |  | 1498 |   | 
        
           |  |  | 1499 |     // Generate a base timestamp for each possible month/week/day.
 | 
        
           |  |  | 1500 |     $times = array();
 | 
        
           |  |  | 1501 |     while ($timeafter < $now) {
 | 
        
           |  |  | 1502 |         $times[] = $timeafter;
 | 
        
           |  |  | 1503 |         if ($timestr == 'daily') {
 | 
        
           |  |  | 1504 |             $timeafter = stats_get_next_day_start($timeafter);
 | 
        
           |  |  | 1505 |         } else if ($timestr == 'weekly') {
 | 
        
           |  |  | 1506 |             $timeafter = stats_get_next_week_start($timeafter);
 | 
        
           |  |  | 1507 |         } else if ($timestr == 'monthly') {
 | 
        
           |  |  | 1508 |             // We can't just simply +1 month because the 31st Jan + 1 month = 2nd of March.
 | 
        
           |  |  | 1509 |             $year = date('Y', $timeafter);
 | 
        
           |  |  | 1510 |             $month = date('m', $timeafter);
 | 
        
           |  |  | 1511 |             $day = date('d', $timeafter);
 | 
        
           |  |  | 1512 |             $dayofnextmonth = $day;
 | 
        
           |  |  | 1513 |             if ($day >= 29) {
 | 
        
           |  |  | 1514 |                 $daysinmonth = date('n', mktime(0, 0, 0, $month+1, 1, $year));
 | 
        
           |  |  | 1515 |                 if ($day > $daysinmonth) {
 | 
        
           |  |  | 1516 |                     $dayofnextmonth = $daysinmonth;
 | 
        
           |  |  | 1517 |                 }
 | 
        
           |  |  | 1518 |             }
 | 
        
           |  |  | 1519 |             $timeafter = mktime($actualtimeshour, 0, 0, $month+1, $dayofnextmonth, $year);
 | 
        
           |  |  | 1520 |         } else {
 | 
        
           |  |  | 1521 |             // This will put us in a never ending loop.
 | 
        
           |  |  | 1522 |             return $stats;
 | 
        
           |  |  | 1523 |         }
 | 
        
           |  |  | 1524 |     }
 | 
        
           |  |  | 1525 |   | 
        
           |  |  | 1526 |     // Add the base timestamp to the statistics if not present.
 | 
        
           |  |  | 1527 |     foreach ($times as $count => $time) {
 | 
        
           |  |  | 1528 |         if (!in_array($time,$actualtimes) && $count != count($times) -1) {
 | 
        
           |  |  | 1529 |             $newobj = new StdClass;
 | 
        
           |  |  | 1530 |             $newobj->timeend = $time;
 | 
        
           |  |  | 1531 |             $newobj->id = 0;
 | 
        
           |  |  | 1532 |             $newobj->roleid = 0;
 | 
        
           |  |  | 1533 |             $newobj->line1 = 0;
 | 
        
           |  |  | 1534 |             if (!empty($line2)) {
 | 
        
           |  |  | 1535 |                 $newobj->line2 = 0;
 | 
        
           |  |  | 1536 |             }
 | 
        
           |  |  | 1537 |             if (!empty($line3)) {
 | 
        
           |  |  | 1538 |                 $newobj->line3 = 0;
 | 
        
           |  |  | 1539 |             }
 | 
        
           |  |  | 1540 |             $newobj->zerofixed = true;
 | 
        
           |  |  | 1541 |             $stats[] = $newobj;
 | 
        
           |  |  | 1542 |         }
 | 
        
           |  |  | 1543 |     }
 | 
        
           |  |  | 1544 |   | 
        
           |  |  | 1545 |     usort($stats,"stats_compare_times");
 | 
        
           |  |  | 1546 |     return $stats;
 | 
        
           |  |  | 1547 | }
 | 
        
           |  |  | 1548 |   | 
        
           |  |  | 1549 | // helper function to sort arrays by $obj->timeend
 | 
        
           |  |  | 1550 | function stats_compare_times($a,$b) {
 | 
        
           |  |  | 1551 |    if ($a->timeend == $b->timeend) {
 | 
        
           |  |  | 1552 |        return 0;
 | 
        
           |  |  | 1553 |    }
 | 
        
           |  |  | 1554 |    return ($a->timeend > $b->timeend) ? -1 : 1;
 | 
        
           |  |  | 1555 | }
 | 
        
           |  |  | 1556 |   | 
        
           |  |  | 1557 | function stats_check_uptodate($courseid=0) {
 | 
        
           |  |  | 1558 |     global $CFG, $DB;
 | 
        
           |  |  | 1559 |   | 
        
           |  |  | 1560 |     if (empty($courseid)) {
 | 
        
           |  |  | 1561 |         $courseid = SITEID;
 | 
        
           |  |  | 1562 |     }
 | 
        
           |  |  | 1563 |   | 
        
           |  |  | 1564 |     $latestday = stats_get_start_from('daily');
 | 
        
           |  |  | 1565 |   | 
        
           |  |  | 1566 |     if ((time() - 60*60*24*2) < $latestday) { // we're ok
 | 
        
           |  |  | 1567 |         return NULL;
 | 
        
           |  |  | 1568 |     }
 | 
        
           |  |  | 1569 |   | 
        
           |  |  | 1570 |     $a = new stdClass();
 | 
        
           |  |  | 1571 |     $a->daysdone = $DB->get_field_sql("SELECT COUNT(DISTINCT(timeend)) FROM {stats_daily}");
 | 
        
           |  |  | 1572 |   | 
        
           |  |  | 1573 |     // how many days between the last day and now?
 | 
        
           |  |  | 1574 |     $a->dayspending = ceil((stats_get_base_daily() - $latestday)/(60*60*24));
 | 
        
           |  |  | 1575 |   | 
        
           |  |  | 1576 |     if ($a->dayspending == 0 && $a->daysdone != 0) {
 | 
        
           |  |  | 1577 |         return NULL; // we've only just started...
 | 
        
           |  |  | 1578 |     }
 | 
        
           |  |  | 1579 |   | 
        
           |  |  | 1580 |     //return error as string
 | 
        
           |  |  | 1581 |     return get_string('statscatchupmode','error',$a);
 | 
        
           |  |  | 1582 | }
 | 
        
           |  |  | 1583 |   | 
        
           |  |  | 1584 | /**
 | 
        
           |  |  | 1585 |  * Create temporary tables to speed up log generation
 | 
        
           |  |  | 1586 |  */
 | 
        
           |  |  | 1587 | function stats_temp_table_create() {
 | 
        
           |  |  | 1588 |     global $CFG, $DB;
 | 
        
           |  |  | 1589 |   | 
        
           |  |  | 1590 |     $dbman = $DB->get_manager(); // We are going to use database_manager services
 | 
        
           |  |  | 1591 |   | 
        
           |  |  | 1592 |     stats_temp_table_drop();
 | 
        
           |  |  | 1593 |   | 
        
           |  |  | 1594 |     $tables = array();
 | 
        
           |  |  | 1595 |   | 
        
           |  |  | 1596 |     /// Define tables user to be created
 | 
        
           |  |  | 1597 |     $table = new xmldb_table('temp_stats_daily');
 | 
        
           |  |  | 1598 |     $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
 | 
        
           |  |  | 1599 |     $table->add_field('courseid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1600 |     $table->add_field('timeend', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1601 |     $table->add_field('roleid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1602 |     $table->add_field('stattype', XMLDB_TYPE_CHAR, 20, null, XMLDB_NOTNULL, null, 'activity');
 | 
        
           |  |  | 1603 |     $table->add_field('stat1', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1604 |     $table->add_field('stat2', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1605 |     $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
 | 
        
           |  |  | 1606 |     $table->add_index('courseid', XMLDB_INDEX_NOTUNIQUE, array('courseid'));
 | 
        
           |  |  | 1607 |     $table->add_index('timeend', XMLDB_INDEX_NOTUNIQUE, array('timeend'));
 | 
        
           |  |  | 1608 |     $table->add_index('roleid', XMLDB_INDEX_NOTUNIQUE, array('roleid'));
 | 
        
           |  |  | 1609 |     $tables['temp_stats_daily'] = $table;
 | 
        
           |  |  | 1610 |   | 
        
           |  |  | 1611 |     $table = new xmldb_table('temp_stats_user_daily');
 | 
        
           |  |  | 1612 |     $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
 | 
        
           |  |  | 1613 |     $table->add_field('courseid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1614 |     $table->add_field('userid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1615 |     $table->add_field('roleid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1616 |     $table->add_field('timeend', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1617 |     $table->add_field('statsreads', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1618 |     $table->add_field('statswrites', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1619 |     $table->add_field('stattype', XMLDB_TYPE_CHAR, 30, null, XMLDB_NOTNULL, null, null);
 | 
        
           |  |  | 1620 |     $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
 | 
        
           |  |  | 1621 |     $table->add_index('courseid', XMLDB_INDEX_NOTUNIQUE, array('courseid'));
 | 
        
           |  |  | 1622 |     $table->add_index('userid', XMLDB_INDEX_NOTUNIQUE, array('userid'));
 | 
        
           |  |  | 1623 |     $table->add_index('timeend', XMLDB_INDEX_NOTUNIQUE, array('timeend'));
 | 
        
           |  |  | 1624 |     $table->add_index('roleid', XMLDB_INDEX_NOTUNIQUE, array('roleid'));
 | 
        
           |  |  | 1625 |     $tables['temp_stats_user_daily'] = $table;
 | 
        
           |  |  | 1626 |   | 
        
           |  |  | 1627 |     $table = new xmldb_table('temp_enroled');
 | 
        
           |  |  | 1628 |     $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
 | 
        
           |  |  | 1629 |     $table->add_field('userid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1630 |     $table->add_field('courseid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1631 |     $table->add_field('roleid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null);
 | 
        
           |  |  | 1632 |     $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
 | 
        
           |  |  | 1633 |     $table->add_index('userid', XMLDB_INDEX_NOTUNIQUE, array('userid'));
 | 
        
           |  |  | 1634 |     $table->add_index('courseid', XMLDB_INDEX_NOTUNIQUE, array('courseid'));
 | 
        
           |  |  | 1635 |     $table->add_index('roleid', XMLDB_INDEX_NOTUNIQUE, array('roleid'));
 | 
        
           |  |  | 1636 |     $table->add_index('useridroleidcourseid', XMLDB_INDEX_NOTUNIQUE, array('userid', 'roleid', 'courseid'));
 | 
        
           |  |  | 1637 |     $tables['temp_enroled'] = $table;
 | 
        
           |  |  | 1638 |   | 
        
           |  |  | 1639 |   | 
        
           |  |  | 1640 |     $table = new xmldb_table('temp_log1');
 | 
        
           |  |  | 1641 |     $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
 | 
        
           |  |  | 1642 |     $table->add_field('userid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1643 |     $table->add_field('course', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
 | 
        
           |  |  | 1644 |     $table->add_field('action', XMLDB_TYPE_CHAR, 40, null, XMLDB_NOTNULL, null, null);
 | 
        
           |  |  | 1645 |     $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
 | 
        
           |  |  | 1646 |     $table->add_index('action', XMLDB_INDEX_NOTUNIQUE, array('action'));
 | 
        
           |  |  | 1647 |     $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
 | 
        
           |  |  | 1648 |     $table->add_index('user', XMLDB_INDEX_NOTUNIQUE, array('userid'));
 | 
        
           |  |  | 1649 |     $table->add_index('usercourseaction', XMLDB_INDEX_NOTUNIQUE, array('userid','course','action'));
 | 
        
           |  |  | 1650 |     $tables['temp_log1'] = $table;
 | 
        
           |  |  | 1651 |   | 
        
           |  |  | 1652 |     /// temp_log2 is exactly the same as temp_log1.
 | 
        
           |  |  | 1653 |     $tables['temp_log2'] = clone $tables['temp_log1'];
 | 
        
           |  |  | 1654 |     $tables['temp_log2']->setName('temp_log2');
 | 
        
           |  |  | 1655 |   | 
        
           |  |  | 1656 |     try {
 | 
        
           |  |  | 1657 |   | 
        
           |  |  | 1658 |         foreach ($tables as $table) {
 | 
        
           |  |  | 1659 |             $dbman->create_temp_table($table);
 | 
        
           |  |  | 1660 |         }
 | 
        
           |  |  | 1661 |   | 
        
           |  |  | 1662 |     } catch (Exception $e) {
 | 
        
           |  |  | 1663 |         mtrace('Temporary table creation failed: '. $e->getMessage());
 | 
        
           |  |  | 1664 |         return false;
 | 
        
           |  |  | 1665 |     }
 | 
        
           |  |  | 1666 |   | 
        
           |  |  | 1667 |     return true;
 | 
        
           |  |  | 1668 | }
 | 
        
           |  |  | 1669 |   | 
        
           |  |  | 1670 | /**
 | 
        
           |  |  | 1671 |  * Deletes summary logs table for stats calculation
 | 
        
           |  |  | 1672 |  */
 | 
        
           |  |  | 1673 | function stats_temp_table_drop() {
 | 
        
           |  |  | 1674 |     global $DB;
 | 
        
           |  |  | 1675 |   | 
        
           |  |  | 1676 |     $dbman = $DB->get_manager();
 | 
        
           |  |  | 1677 |   | 
        
           |  |  | 1678 |     $tables = array('temp_log1', 'temp_log2', 'temp_stats_daily', 'temp_stats_user_daily', 'temp_enroled');
 | 
        
           |  |  | 1679 |   | 
        
           |  |  | 1680 |     foreach ($tables as $name) {
 | 
        
           |  |  | 1681 |   | 
        
           |  |  | 1682 |         if ($dbman->table_exists($name)) {
 | 
        
           |  |  | 1683 |             $table = new xmldb_table($name);
 | 
        
           |  |  | 1684 |   | 
        
           |  |  | 1685 |             try {
 | 
        
           |  |  | 1686 |                 $dbman->drop_table($table);
 | 
        
           |  |  | 1687 |             } catch (Exception $e) {
 | 
        
           |  |  | 1688 |                 mtrace("Error occured while dropping temporary tables!");
 | 
        
           |  |  | 1689 |             }
 | 
        
           |  |  | 1690 |         }
 | 
        
           |  |  | 1691 |     }
 | 
        
           |  |  | 1692 | }
 | 
        
           |  |  | 1693 |   | 
        
           |  |  | 1694 | /**
 | 
        
           |  |  | 1695 |  * Fills the temporary stats tables with new data
 | 
        
           |  |  | 1696 |  *
 | 
        
           |  |  | 1697 |  * This function is meant to be called once at the start of stats generation
 | 
        
           |  |  | 1698 |  *
 | 
        
           |  |  | 1699 |  * @param int timestart timestamp of the start time of logs view
 | 
        
           |  |  | 1700 |  * @param int timeend timestamp of the end time of logs view
 | 
        
           |  |  | 1701 |  * @return bool success (true) or failure(false)
 | 
        
           |  |  | 1702 |  */
 | 
        
           |  |  | 1703 | function stats_temp_table_setup() {
 | 
        
           |  |  | 1704 |     global $DB;
 | 
        
           |  |  | 1705 |   | 
        
           |  |  | 1706 |     $sql = "INSERT INTO {temp_enroled} (userid, courseid, roleid)
 | 
        
           |  |  | 1707 |   | 
        
           |  |  | 1708 |                SELECT ue.userid, e.courseid, ra.roleid
 | 
        
           |  |  | 1709 |                 FROM {role_assignments} ra
 | 
        
           |  |  | 1710 |                 JOIN {context} c ON (c.id = ra.contextid AND c.contextlevel = :courselevel)
 | 
        
           |  |  | 1711 |                 JOIN {enrol} e ON e.courseid = c.instanceid
 | 
        
           |  |  | 1712 |                 JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid)";
 | 
        
           |  |  | 1713 |   | 
        
           |  |  | 1714 |     return stats_run_query($sql, array('courselevel' => CONTEXT_COURSE));
 | 
        
           |  |  | 1715 | }
 | 
        
           |  |  | 1716 |   | 
        
           |  |  | 1717 | /**
 | 
        
           |  |  | 1718 |  * Fills the temporary stats tables with new data
 | 
        
           |  |  | 1719 |  *
 | 
        
           |  |  | 1720 |  * This function is meant to be called to get a new day of data
 | 
        
           |  |  | 1721 |  *
 | 
        
           |  |  | 1722 |  * @param int timestamp of the start time of logs view
 | 
        
           |  |  | 1723 |  * @param int timestamp of the end time of logs view
 | 
        
           |  |  | 1724 |  * @return bool success (true) or failure(false)
 | 
        
           |  |  | 1725 |  */
 | 
        
           |  |  | 1726 | function stats_temp_table_fill($timestart, $timeend) {
 | 
        
           |  |  | 1727 |     global $DB;
 | 
        
           |  |  | 1728 |   | 
        
           |  |  | 1729 |     // First decide from where we want the data.
 | 
        
           |  |  | 1730 |   | 
        
           |  |  | 1731 |     $params = array('timestart' => $timestart,
 | 
        
           |  |  | 1732 |                     'timeend' => $timeend,
 | 
        
           |  |  | 1733 |                     'participating' => \core\event\base::LEVEL_PARTICIPATING,
 | 
        
           |  |  | 1734 |                     'teaching' => \core\event\base::LEVEL_TEACHING,
 | 
        
           |  |  | 1735 |                     'loginevent1' => '\core\event\user_loggedin',
 | 
        
           |  |  | 1736 |                     'loginevent2' => '\core\event\user_loggedin',
 | 
        
           |  |  | 1737 |     );
 | 
        
           |  |  | 1738 |   | 
        
           |  |  | 1739 |     $filled = false;
 | 
        
           |  |  | 1740 |     $manager = get_log_manager();
 | 
        
           |  |  | 1741 |     $stores = $manager->get_readers();
 | 
        
           |  |  | 1742 |     foreach ($stores as $store) {
 | 
        
           |  |  | 1743 |         if ($store instanceof \core\log\sql_internal_table_reader) {
 | 
        
           |  |  | 1744 |             $logtable = $store->get_internal_log_table_name();
 | 
        
           |  |  | 1745 |             if (!$logtable) {
 | 
        
           |  |  | 1746 |                 continue;
 | 
        
           |  |  | 1747 |             }
 | 
        
           |  |  | 1748 |   | 
        
           |  |  | 1749 |             $sql = "SELECT COUNT('x')
 | 
        
           |  |  | 1750 |                       FROM {{$logtable}}
 | 
        
           |  |  | 1751 |                      WHERE timecreated >= :timestart AND timecreated < :timeend";
 | 
        
           |  |  | 1752 |   | 
        
           |  |  | 1753 |             if (!$DB->get_field_sql($sql, $params)) {
 | 
        
           |  |  | 1754 |                 continue;
 | 
        
           |  |  | 1755 |             }
 | 
        
           |  |  | 1756 |   | 
        
           |  |  | 1757 |             // Let's fake the old records using new log data.
 | 
        
           |  |  | 1758 |             // We want only data relevant to educational process
 | 
        
           |  |  | 1759 |             // done by real users.
 | 
        
           |  |  | 1760 |   | 
        
           |  |  | 1761 |             $sql = "INSERT INTO {temp_log1} (userid, course, action)
 | 
        
           |  |  | 1762 |   | 
        
           |  |  | 1763 |             SELECT userid,
 | 
        
           |  |  | 1764 |                    CASE
 | 
        
           |  |  | 1765 |                       WHEN courseid IS NULL THEN ".SITEID."
 | 
        
           |  |  | 1766 |                       WHEN courseid = 0 THEN ".SITEID."
 | 
        
           |  |  | 1767 |                       ELSE courseid
 | 
        
           |  |  | 1768 |                    END,
 | 
        
           |  |  | 1769 |                    CASE
 | 
        
           |  |  | 1770 |                        WHEN eventname = :loginevent1 THEN 'login'
 | 
        
           |  |  | 1771 |                        WHEN crud = 'r' THEN 'view'
 | 
        
           |  |  | 1772 |                        ELSE 'update'
 | 
        
           |  |  | 1773 |                    END
 | 
        
           |  |  | 1774 |               FROM {{$logtable}}
 | 
        
           |  |  | 1775 |              WHERE timecreated >= :timestart AND timecreated < :timeend
 | 
        
           |  |  | 1776 |                    AND (origin = 'web' OR origin = 'ws')
 | 
        
           |  |  | 1777 |                    AND (edulevel = :participating OR edulevel = :teaching OR eventname = :loginevent2)";
 | 
        
           |  |  | 1778 |   | 
        
           |  |  | 1779 |             $DB->execute($sql, $params);
 | 
        
           |  |  | 1780 |             $filled = true;
 | 
        
           |  |  | 1781 |         }
 | 
        
           |  |  | 1782 |     }
 | 
        
           |  |  | 1783 |   | 
        
           |  |  | 1784 |     if (!$filled) {
 | 
        
           |  |  | 1785 |         // Fallback to legacy data.
 | 
        
           |  |  | 1786 |         $sql = "INSERT INTO {temp_log1} (userid, course, action)
 | 
        
           |  |  | 1787 |   | 
        
           |  |  | 1788 |             SELECT userid, course, action
 | 
        
           |  |  | 1789 |               FROM {log}
 | 
        
           |  |  | 1790 |              WHERE time >= :timestart AND time < :timeend";
 | 
        
           |  |  | 1791 |   | 
        
           |  |  | 1792 |         $DB->execute($sql, $params);
 | 
        
           |  |  | 1793 |     }
 | 
        
           |  |  | 1794 |   | 
        
           |  |  | 1795 |     $sql = 'INSERT INTO {temp_log2} (userid, course, action)
 | 
        
           |  |  | 1796 |   | 
        
           |  |  | 1797 |             SELECT userid, course, action FROM {temp_log1}';
 | 
        
           |  |  | 1798 |   | 
        
           |  |  | 1799 |     $DB->execute($sql);
 | 
        
           |  |  | 1800 |   | 
        
           |  |  | 1801 |     // We have just loaded all the temp tables, collect statistics for that.
 | 
        
           |  |  | 1802 |     $DB->update_temp_table_stats();
 | 
        
           |  |  | 1803 |   | 
        
           |  |  | 1804 |     return true;
 | 
        
           |  |  | 1805 | }
 | 
        
           |  |  | 1806 |   | 
        
           |  |  | 1807 |   | 
        
           |  |  | 1808 | /**
 | 
        
           |  |  | 1809 |  * Deletes summary logs table for stats calculation
 | 
        
           |  |  | 1810 |  *
 | 
        
           |  |  | 1811 |  * @return bool success (true) or failure(false)
 | 
        
           |  |  | 1812 |  */
 | 
        
           |  |  | 1813 | function stats_temp_table_clean() {
 | 
        
           |  |  | 1814 |     global $DB;
 | 
        
           |  |  | 1815 |   | 
        
           |  |  | 1816 |     $sql = array();
 | 
        
           |  |  | 1817 |   | 
        
           |  |  | 1818 |     $sql['up1'] = 'INSERT INTO {stats_daily} (courseid, roleid, stattype, timeend, stat1, stat2)
 | 
        
           |  |  | 1819 |   | 
        
           |  |  | 1820 |                    SELECT courseid, roleid, stattype, timeend, stat1, stat2 FROM {temp_stats_daily}';
 | 
        
           |  |  | 1821 |   | 
        
           |  |  | 1822 |     $sql['up2'] = 'INSERT INTO {stats_user_daily}
 | 
        
           |  |  | 1823 |                                (courseid, userid, roleid, timeend, statsreads, statswrites, stattype)
 | 
        
           |  |  | 1824 |   | 
        
           |  |  | 1825 |                    SELECT courseid, userid, roleid, timeend, statsreads, statswrites, stattype
 | 
        
           |  |  | 1826 |                      FROM {temp_stats_user_daily}';
 | 
        
           |  |  | 1827 |   | 
        
           |  |  | 1828 |     foreach ($sql as $id => $query) {
 | 
        
           |  |  | 1829 |         if (! stats_run_query($query)) {
 | 
        
           |  |  | 1830 |             mtrace("Error during table cleanup!");
 | 
        
           |  |  | 1831 |             return false;
 | 
        
           |  |  | 1832 |         }
 | 
        
           |  |  | 1833 |     }
 | 
        
           |  |  | 1834 |   | 
        
           |  |  | 1835 |     $tables = array('temp_log1', 'temp_log2', 'temp_stats_daily', 'temp_stats_user_daily');
 | 
        
           |  |  | 1836 |   | 
        
           |  |  | 1837 |     foreach ($tables as $name) {
 | 
        
           |  |  | 1838 |         $DB->delete_records($name);
 | 
        
           |  |  | 1839 |     }
 | 
        
           |  |  | 1840 |   | 
        
           |  |  | 1841 |     return true;
 | 
        
           |  |  | 1842 | }
 |