|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00025 defined('MOODLE_INTERNAL') || die(); 00026 00029 define('STATS_REPORT_LOGINS',1); // double impose logins and unique logins on a line graph. site course only. 00030 define('STATS_REPORT_READS',2); // double impose student reads and teacher reads on a line graph. 00031 define('STATS_REPORT_WRITES',3); // double impose student writes and teacher writes on a line graph. 00032 define('STATS_REPORT_ACTIVITY',4); // 2+3 added up, teacher vs student. 00033 define('STATS_REPORT_ACTIVITYBYROLE',5); // all activity, reads vs writes, selected by role. 00034 00035 // user level stats reports. 00036 define('STATS_REPORT_USER_ACTIVITY',7); 00037 define('STATS_REPORT_USER_ALLACTIVITY',8); 00038 define('STATS_REPORT_USER_LOGINS',9); 00039 define('STATS_REPORT_USER_VIEW',10); // this is the report you see on the user profile. 00040 00041 // admin only ranking stats reports 00042 define('STATS_REPORT_ACTIVE_COURSES',11); 00043 define('STATS_REPORT_ACTIVE_COURSES_WEIGHTED',12); 00044 define('STATS_REPORT_PARTICIPATORY_COURSES',13); 00045 define('STATS_REPORT_PARTICIPATORY_COURSES_RW',14); 00046 00047 // start after 0 = show dailies. 00048 define('STATS_TIME_LASTWEEK',1); 00049 define('STATS_TIME_LAST2WEEKS',2); 00050 define('STATS_TIME_LAST3WEEKS',3); 00051 define('STATS_TIME_LAST4WEEKS',4); 00052 00053 // start after 10 = show weeklies 00054 define('STATS_TIME_LAST2MONTHS',12); 00055 00056 define('STATS_TIME_LAST3MONTHS',13); 00057 define('STATS_TIME_LAST4MONTHS',14); 00058 define('STATS_TIME_LAST5MONTHS',15); 00059 define('STATS_TIME_LAST6MONTHS',16); 00060 00061 // start after 20 = show monthlies 00062 define('STATS_TIME_LAST7MONTHS',27); 00063 define('STATS_TIME_LAST8MONTHS',28); 00064 define('STATS_TIME_LAST9MONTHS',29); 00065 define('STATS_TIME_LAST10MONTHS',30); 00066 define('STATS_TIME_LAST11MONTHS',31); 00067 define('STATS_TIME_LASTYEAR',32); 00068 00069 // different modes for what reports to offer 00070 define('STATS_MODE_GENERAL',1); 00071 define('STATS_MODE_DETAILED',2); 00072 define('STATS_MODE_RANKED',3); // admins only - ranks courses 00073 00078 function stats_daily_progress($ident) { 00079 static $start = 0; 00080 static $init = 0; 00081 00082 if ($ident == 'init') { 00083 $init = $start = time(); 00084 return; 00085 } 00086 00087 $elapsed = time() - $start; 00088 $start = time(); 00089 00090 if (debugging('', DEBUG_ALL)) { 00091 mtrace("$ident:$elapsed ", ''); 00092 } else { 00093 mtrace('.', ''); 00094 } 00095 } 00096 00102 function stats_cron_daily($maxdays=1) { 00103 global $CFG, $DB; 00104 00105 $now = time(); 00106 00107 $fpcontext = get_context_instance(CONTEXT_COURSE, SITEID, MUST_EXIST); 00108 00109 // read last execution date from db 00110 if (!$timestart = get_config(NULL, 'statslastdaily')) { 00111 $timestart = stats_get_base_daily(stats_get_start_from('daily')); 00112 set_config('statslastdaily', $timestart); 00113 } 00114 00115 // calculate scheduled time 00116 $scheduledtime = stats_get_base_daily() + $CFG->statsruntimestarthour*60*60 + $CFG->statsruntimestartminute*60; 00117 00118 // Note: This will work fine for sites running cron each 4 hours or less (hopefully, 99.99% of sites). MDL-16709 00119 // check to make sure we're due to run, at least 20 hours after last run 00120 if (isset($CFG->statslastexecution) and ((time() - 20*60*60) < $CFG->statslastexecution)) { 00121 mtrace("...preventing stats to run, last execution was less than 20 hours ago."); 00122 return false; 00123 // also check that we are a max of 4 hours after scheduled time, stats won't run after that 00124 } else if (time() > $scheduledtime + 4*60*60) { 00125 mtrace("...preventing stats to run, more than 4 hours since scheduled time."); 00126 return false; 00127 } else { 00128 set_config('statslastexecution', time()); 00129 } 00130 00131 $nextmidnight = stats_get_next_day_start($timestart); 00132 00133 // are there any days that need to be processed? 00134 if ($now < $nextmidnight) { 00135 return true; // everything ok and up-to-date 00136 } 00137 00138 00139 $timeout = empty($CFG->statsmaxruntime) ? 60*60*24 : $CFG->statsmaxruntime; 00140 00141 if (!set_cron_lock('statsrunning', $now + $timeout)) { 00142 return false; 00143 } 00144 00145 // first delete entries that should not be there yet 00146 $DB->delete_records_select('stats_daily', "timeend > $timestart"); 00147 $DB->delete_records_select('stats_user_daily', "timeend > $timestart"); 00148 00149 // Read in a few things we'll use later 00150 $viewactions = stats_get_action_names('view'); 00151 $postactions = stats_get_action_names('post'); 00152 00153 $guest = (int)$CFG->siteguest; 00154 $guestrole = (int)$CFG->guestroleid; 00155 $defaultfproleid = (int)$CFG->defaultfrontpageroleid; 00156 00157 mtrace("Running daily statistics gathering, starting at $timestart:"); 00158 00159 $days = 0; 00160 $failed = false; // failed stats flag 00161 00162 while ($now > $nextmidnight) { 00163 if ($days >= $maxdays) { 00164 mtrace("...stopping early, reached maximum number of $maxdays days - will continue next time."); 00165 set_cron_lock('statsrunning', null); 00166 return false; 00167 } 00168 00169 $days++; 00170 @set_time_limit($timeout - 200); 00171 00172 if ($days > 1) { 00173 // move the lock 00174 set_cron_lock('statsrunning', time() + $timeout, true); 00175 } 00176 00177 $daystart = time(); 00178 00179 $timesql = "l.time >= $timestart AND l.time < $nextmidnight"; 00180 $timesql1 = "l1.time >= $timestart AND l1.time < $nextmidnight"; 00181 $timesql2 = "l2.time >= $timestart AND l2.time < $nextmidnight"; 00182 00183 stats_daily_progress('init'); 00184 00185 00187 $sql = "SELECT 'x' 00188 FROM {log} l 00189 WHERE $timesql"; 00190 $logspresent = $DB->get_records_sql($sql, null, 0, 1); 00191 00193 $sql = "INSERT INTO {stats_user_daily} (stattype, timeend, courseid, userid, statsreads) 00194 00195 SELECT 'logins', timeend, courseid, userid, count(statsreads) 00196 FROM ( 00197 SELECT $nextmidnight AS timeend, ".SITEID." AS courseid, l.userid, l.id AS statsreads 00198 FROM {log} l 00199 WHERE action = 'login' AND $timesql 00200 ) inline_view 00201 GROUP BY timeend, courseid, userid 00202 HAVING count(statsreads) > 0"; 00203 00204 if ($logspresent and !$DB->execute($sql)) { 00205 $failed = true; 00206 break; 00207 } 00208 stats_daily_progress('1'); 00209 00210 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00211 00212 SELECT 'logins' AS stattype, $nextmidnight AS timeend, ".SITEID." as courseid, 0, 00213 COALESCE((SELECT SUM(statsreads) 00214 FROM {stats_user_daily} s1 00215 WHERE s1.stattype = 'logins' AND timeend = $nextmidnight), 0) AS stat1, 00216 (SELECT COUNT('x') 00217 FROM {stats_user_daily} s2 00218 WHERE s2.stattype = 'logins' AND timeend = $nextmidnight) AS stat2" . 00219 $DB->sql_null_from_clause(); 00220 00221 if ($logspresent and !$DB->execute($sql)) { 00222 $failed = true; 00223 break; 00224 } 00225 stats_daily_progress('2'); 00226 00227 00228 // Enrolments and active enrolled users 00229 // 00230 // Unfortunately, we do not know how many users were registered 00231 // at given times in history :-( 00232 // - stat1: enrolled users 00233 // - stat2: enrolled users active in this period 00234 // - SITEID is special case here, because it's all about default enrolment 00235 // in that case, we'll count non-deleted users. 00236 // 00237 00238 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00239 00240 SELECT 'enrolments', timeend, courseid, roleid, COUNT(DISTINCT userid), 0 00241 FROM ( 00242 SELECT $nextmidnight AS timeend, e.courseid, ra.roleid, ue.userid 00243 FROM {role_assignments} ra 00244 JOIN {context} c ON (c.id = ra.contextid AND c.contextlevel = :courselevel) 00245 JOIN {enrol} e ON e.courseid = c.instanceid 00246 JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid) 00247 ) inline_view 00248 GROUP BY timeend, courseid, roleid"; 00249 00250 if (!$DB->execute($sql, array('courselevel'=>CONTEXT_COURSE))) { 00251 $failed = true; 00252 break; 00253 } 00254 stats_daily_progress('3'); 00255 00256 // using table alias in UPDATE does not work in pg < 8.2 00257 $sql = "UPDATE {stats_daily} 00258 SET stat2 = (SELECT COUNT(DISTINCT ra.userid) 00259 FROM {role_assignments} ra 00260 JOIN {context} c ON (c.id = ra.contextid AND c.contextlevel = :courselevel) 00261 JOIN {enrol} e ON e.courseid = c.instanceid 00262 JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid) 00263 WHERE ra.roleid = {stats_daily}.roleid AND 00264 e.courseid = {stats_daily}.courseid AND 00265 EXISTS (SELECT 'x' 00266 FROM {log} l 00267 WHERE l.course = {stats_daily}.courseid AND 00268 l.userid = ra.userid AND $timesql)) 00269 WHERE {stats_daily}.stattype = 'enrolments' AND 00270 {stats_daily}.timeend = $nextmidnight AND 00271 {stats_daily}.courseid IN 00272 (SELECT DISTINCT l.course 00273 FROM {log} l 00274 WHERE $timesql)"; 00275 00276 if (!$DB->execute($sql, array('courselevel'=>CONTEXT_COURSE))) { 00277 $failed = true; 00278 break; 00279 } 00280 stats_daily_progress('4'); 00281 00283 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00284 00285 SELECT 'enrolments', timeend, id, nroleid, COUNT(DISTINCT userid), 0 00286 FROM ( 00287 SELECT $nextmidnight AS timeend, e.courseid AS id, 0 AS nroleid, ue.userid 00288 FROM {enrol} e 00289 JOIN {user_enrolments} ue ON ue.enrolid = e.id 00290 ) inline_view 00291 GROUP BY timeend, id, nroleid 00292 HAVING COUNT(DISTINCT userid) > 0"; 00293 00294 if ($logspresent and !$DB->execute($sql)) { 00295 $failed = true; 00296 break; 00297 } 00298 stats_daily_progress('5'); 00299 00300 $sql = "UPDATE {stats_daily} 00301 SET stat2 = (SELECT COUNT(DISTINCT ue.userid) 00302 FROM {enrol} e 00303 JOIN {user_enrolments} ue ON ue.enrolid = e.id 00304 WHERE e.courseid = {stats_daily}.courseid AND 00305 EXISTS (SELECT 'x' 00306 FROM {log} l 00307 WHERE l.course = {stats_daily}.courseid AND 00308 l.userid = ue.userid AND $timesql)) 00309 WHERE {stats_daily}.stattype = 'enrolments' AND 00310 {stats_daily}.timeend = $nextmidnight AND 00311 {stats_daily}.roleid = 0 AND 00312 {stats_daily}.courseid IN 00313 (SELECT l.course 00314 FROM {log} l 00315 WHERE $timesql AND l.course <> ".SITEID.")"; 00316 00317 if ($logspresent and !$DB->execute($sql, array())) { 00318 $failed = true; 00319 break; 00320 } 00321 stats_daily_progress('6'); 00322 00324 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00325 00326 SELECT 'enrolments', $nextmidnight, ".SITEID.", 0, 00327 (SELECT COUNT('x') 00328 FROM {user} u 00329 WHERE u.deleted = 0) AS stat1, 00330 (SELECT COUNT(DISTINCT u.id) 00331 FROM {user} u 00332 JOIN {log} l ON l.userid = u.id 00333 WHERE u.deleted = 0 AND $timesql) AS stat2" . 00334 $DB->sql_null_from_clause(); 00335 00336 if ($logspresent and !$DB->execute($sql)) { 00337 $failed = true; 00338 break; 00339 } 00340 stats_daily_progress('7'); 00341 00343 if ($defaultfproleid) { 00344 // first remove default frontpage role counts if created by previous query 00345 $sql = "DELETE 00346 FROM {stats_daily} 00347 WHERE stattype = 'enrolments' AND courseid = ".SITEID." AND 00348 roleid = $defaultfproleid AND timeend = $nextmidnight"; 00349 if ($logspresent and !$DB->execute($sql)) { 00350 $failed = true; 00351 break; 00352 } 00353 stats_daily_progress('8'); 00354 00355 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00356 00357 SELECT 'enrolments', $nextmidnight, ".SITEID.", $defaultfproleid, 00358 (SELECT COUNT('x') 00359 FROM {user} u 00360 WHERE u.deleted = 0) AS stat1, 00361 (SELECT COUNT(DISTINCT u.id) 00362 FROM {user} u 00363 JOIN {log} l ON l.userid = u.id 00364 WHERE u.deleted = 0 AND $timesql) AS stat2" . 00365 $DB->sql_null_from_clause();; 00366 00367 if ($logspresent and !$DB->execute($sql)) { 00368 $failed = true; 00369 break; 00370 } 00371 stats_daily_progress('9'); 00372 00373 } else { 00374 stats_daily_progress('x'); 00375 stats_daily_progress('x'); 00376 } 00377 00378 00379 00381 list($viewactionssql, $params1) = $DB->get_in_or_equal($viewactions, SQL_PARAMS_NAMED, 'view'); 00382 list($postactionssql, $params2) = $DB->get_in_or_equal($postactions, SQL_PARAMS_NAMED, 'post'); 00383 $sql = "INSERT INTO {stats_user_daily} (stattype, timeend, courseid, userid, statsreads, statswrites) 00384 00385 SELECT 'activity' AS stattype, $nextmidnight AS timeend, d.courseid, d.userid, 00386 (SELECT COUNT('x') 00387 FROM {log} l 00388 WHERE l.userid = d.userid AND 00389 l.course = d.courseid AND $timesql AND 00390 l.action $viewactionssql) AS statsreads, 00391 (SELECT COUNT('x') 00392 FROM {log} l 00393 WHERE l.userid = d.userid AND 00394 l.course = d.courseid AND $timesql AND 00395 l.action $postactionssql) AS statswrites 00396 FROM (SELECT DISTINCT u.id AS userid, l.course AS courseid 00397 FROM {user} u, {log} l 00398 WHERE u.id = l.userid AND $timesql 00399 UNION 00400 SELECT 0 AS userid, ".SITEID." AS courseid" . $DB->sql_null_from_clause() . ") d"; 00401 // can not use group by here because pg can not handle it :-( 00402 00403 if ($logspresent and !$DB->execute($sql, array_merge($params1, $params2))) { 00404 $failed = true; 00405 break; 00406 } 00407 stats_daily_progress('10'); 00408 00409 00411 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00412 00413 SELECT 'activity' AS stattype, $nextmidnight AS timeend, c.id AS courseid, 0, 00414 (SELECT COUNT('x') 00415 FROM {log} l1 00416 WHERE l1.course = c.id AND l1.action $viewactionssql AND 00417 $timesql1) AS stat1, 00418 (SELECT COUNT('x') 00419 FROM {log} l2 00420 WHERE l2.course = c.id AND l2.action $postactionssql AND 00421 $timesql2) AS stat2 00422 FROM {course} c 00423 WHERE EXISTS (SELECT 'x' 00424 FROM {log} l 00425 WHERE l.course = c.id and $timesql)"; 00426 00427 if ($logspresent and !$DB->execute($sql, array_merge($params1, $params2))) { 00428 $failed = true; 00429 break; 00430 } 00431 stats_daily_progress('11'); 00432 00433 00435 00436 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00437 00438 SELECT 'activity', timeend, courseid, roleid, SUM(statsreads), SUM(statswrites) 00439 FROM ( 00440 SELECT $nextmidnight AS timeend, pl.courseid, pl.roleid, sud.statsreads, sud.statswrites 00441 FROM {stats_user_daily} sud, 00442 (SELECT DISTINCT ra.userid, ra.roleid, e.courseid 00443 FROM {role_assignments} ra 00444 JOIN {context} c ON (c.id = ra.contextid AND c.contextlevel = :courselevel) 00445 JOIN {enrol} e ON e.courseid = c.instanceid 00446 JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid) 00447 WHERE ra.roleid <> $guestrole AND 00448 ra.userid <> $guest 00449 ) pl 00450 WHERE sud.userid = pl.userid AND 00451 sud.courseid = pl.courseid AND 00452 sud.timeend = $nextmidnight AND 00453 sud.stattype='activity' 00454 ) inline_view 00455 GROUP BY timeend, courseid, roleid 00456 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0"; 00457 00458 if ($logspresent and !$DB->execute($sql, array('courselevel'=>CONTEXT_COURSE))) { 00459 $failed = true; 00460 break; 00461 } 00462 stats_daily_progress('12'); 00463 00466 00467 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00468 00469 SELECT 'activity', timeend, courseid, nroleid, SUM(statsreads), SUM(statswrites) 00470 FROM ( 00471 SELECT $nextmidnight AS timeend, sud.courseid, $guestrole AS nroleid, sud.statsreads, sud.statswrites 00472 FROM {stats_user_daily} sud 00473 WHERE sud.timeend = $nextmidnight AND sud.courseid <> ".SITEID." AND 00474 sud.stattype='activity' AND 00475 (sud.userid = $guest OR sud.userid 00476 NOT IN (SELECT ue.userid 00477 FROM {user_enrolments} ue 00478 JOIN {enrol} e ON ue.enrolid = e.id 00479 WHERE e.courseid = sud.courseid)) 00480 ) inline_view 00481 GROUP BY timeend, courseid, nroleid 00482 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0"; 00483 00484 if ($logspresent and !$DB->execute($sql, array())) { 00485 $failed = true; 00486 break; 00487 } 00488 stats_daily_progress('13'); 00489 00490 00492 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00493 00494 SELECT 'activity', timeend, courseid, roleid, SUM(statsreads), SUM(statswrites) 00495 FROM ( 00496 SELECT $nextmidnight AS timeend, pl.courseid, pl.roleid, sud.statsreads, sud.statswrites 00497 FROM {stats_user_daily} sud, 00498 (SELECT DISTINCT ra.userid, ra.roleid, c.instanceid AS courseid 00499 FROM {role_assignments} ra 00500 JOIN {context} c ON c.id = ra.contextid 00501 WHERE ra.contextid = :fpcontext AND 00502 ra.roleid <> $defaultfproleid AND 00503 ra.roleid <> $guestrole AND 00504 ra.userid <> $guest 00505 ) pl 00506 WHERE sud.userid = pl.userid AND 00507 sud.courseid = pl.courseid AND 00508 sud.timeend = $nextmidnight AND 00509 sud.stattype='activity' 00510 ) inline_view 00511 GROUP BY timeend, courseid, roleid 00512 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0"; 00513 00514 if ($logspresent and !$DB->execute($sql, array('fpcontext'=>$fpcontext->id))) { 00515 $failed = true; 00516 break; 00517 } 00518 stats_daily_progress('14'); 00519 00520 00522 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00523 00524 SELECT 'activity', timeend, courseid, nroleid, SUM(statsreads), SUM(statswrites) 00525 FROM ( 00526 SELECT sud.timeend AS timeend, sud.courseid, $defaultfproleid AS nroleid, sud.statsreads, sud.statswrites 00527 FROM {stats_user_daily} sud 00528 WHERE sud.timeend = :nextm AND sud.courseid = :siteid AND 00529 sud.stattype='activity' AND 00530 sud.userid <> $guest AND sud.userid <> 0 AND sud.userid 00531 NOT IN (SELECT ra.userid 00532 FROM {role_assignments} ra 00533 WHERE ra.roleid <> $guestrole AND 00534 ra.roleid <> $defaultfproleid AND ra.contextid = :fpcontext) 00535 ) inline_view 00536 GROUP BY timeend, courseid, nroleid 00537 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0"; 00538 00539 if ($logspresent and !$DB->execute($sql, array('fpcontext'=>$fpcontext->id, 'siteid'=>SITEID, 'nextm'=>$nextmidnight))) { 00540 $failed = true; 00541 break; 00542 } 00543 stats_daily_progress('15'); 00544 00546 $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2) 00547 00548 SELECT 'activity', timeend, courseid, nroleid, SUM(statsreads), SUM(statswrites) 00549 FROM ( 00550 SELECT $nextmidnight AS timeend, ".SITEID." AS courseid, $guestrole AS nroleid, pl.statsreads, pl.statswrites 00551 FROM ( 00552 SELECT sud.statsreads, sud.statswrites 00553 FROM {stats_user_daily} sud 00554 WHERE (sud.userid = $guest OR sud.userid = 0) AND 00555 sud.timeend = $nextmidnight AND sud.courseid = ".SITEID." AND 00556 sud.stattype='activity' 00557 ) pl 00558 ) inline_view 00559 GROUP BY timeend, courseid, nroleid 00560 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0"; 00561 00562 if ($logspresent and !$DB->execute($sql)) { 00563 $failed = true; 00564 break; 00565 } 00566 stats_daily_progress('16'); 00567 00568 // remember processed days 00569 set_config('statslastdaily', $nextmidnight); 00570 mtrace(" finished until $nextmidnight: ".userdate($nextmidnight)." (in ".(time()-$daystart)." s)"); 00571 00572 $timestart = $nextmidnight; 00573 $nextmidnight = stats_get_next_day_start($nextmidnight); 00574 } 00575 00576 set_cron_lock('statsrunning', null); 00577 00578 if ($failed) { 00579 $days--; 00580 mtrace("...error occurred, completed $days days of statistics."); 00581 return false; 00582 00583 } else { 00584 mtrace("...completed $days days of statistics."); 00585 return true; 00586 } 00587 } 00588 00589 00594 function stats_cron_weekly() { 00595 global $CFG, $DB; 00596 00597 $now = time(); 00598 00599 // read last execution date from db 00600 if (!$timestart = get_config(NULL, 'statslastweekly')) { 00601 $timestart = stats_get_base_daily(stats_get_start_from('weekly')); 00602 set_config('statslastweekly', $timestart); 00603 } 00604 00605 $nextstartweek = stats_get_next_week_start($timestart); 00606 00607 // are there any weeks that need to be processed? 00608 if ($now < $nextstartweek) { 00609 return true; // everything ok and up-to-date 00610 } 00611 00612 $timeout = empty($CFG->statsmaxruntime) ? 60*60*24 : $CFG->statsmaxruntime; 00613 00614 if (!set_cron_lock('statsrunning', $now + $timeout)) { 00615 return false; 00616 } 00617 00618 // fisrt delete entries that should not be there yet 00619 $DB->delete_records_select('stats_weekly', "timeend > $timestart"); 00620 $DB->delete_records_select('stats_user_weekly', "timeend > $timestart"); 00621 00622 mtrace("Running weekly statistics gathering, starting at $timestart:"); 00623 00624 $weeks = 0; 00625 while ($now > $nextstartweek) { 00626 @set_time_limit($timeout - 200); 00627 $weeks++; 00628 00629 if ($weeks > 1) { 00630 // move the lock 00631 set_cron_lock('statsrunning', time() + $timeout, true); 00632 } 00633 00634 $logtimesql = "l.time >= $timestart AND l.time < $nextstartweek"; 00635 $stattimesql = "timeend > $timestart AND timeend <= $nextstartweek"; 00636 00638 $sql = "INSERT INTO {stats_user_weekly} (stattype, timeend, courseid, userid, statsreads) 00639 00640 SELECT 'logins', timeend, courseid, userid, COUNT(statsreads) 00641 FROM ( 00642 SELECT $nextstartweek AS timeend, ".SITEID." as courseid, l.userid, l.id AS statsreads 00643 FROM {log} l 00644 WHERE action = 'login' AND $logtimesql 00645 ) inline_view 00646 GROUP BY timeend, courseid, userid 00647 HAVING count(statsreads) > 0"; 00648 00649 $DB->execute($sql); 00650 00651 $sql = "INSERT INTO {stats_weekly} (stattype, timeend, courseid, roleid, stat1, stat2) 00652 00653 SELECT 'logins' AS stattype, $nextstartweek AS timeend, ".SITEID." as courseid, 0, 00654 COALESCE((SELECT SUM(statsreads) 00655 FROM {stats_user_weekly} s1 00656 WHERE s1.stattype = 'logins' AND timeend = $nextstartweek), 0) AS nstat1, 00657 (SELECT COUNT('x') 00658 FROM {stats_user_weekly} s2 00659 WHERE s2.stattype = 'logins' AND timeend = $nextstartweek) AS nstat2" . 00660 $DB->sql_null_from_clause(); 00661 00662 $DB->execute($sql); 00663 00664 00666 $sql = "INSERT INTO {stats_weekly} (stattype, timeend, courseid, roleid, stat1, stat2) 00667 00668 SELECT 'enrolments', ntimeend, courseid, roleid, " . $DB->sql_ceil('AVG(stat1)') . ", " . $DB->sql_ceil('AVG(stat2)') . " 00669 FROM ( 00670 SELECT $nextstartweek AS ntimeend, courseid, roleid, stat1, stat2 00671 FROM {stats_daily} sd 00672 WHERE stattype = 'enrolments' AND $stattimesql 00673 ) inline_view 00674 GROUP BY ntimeend, courseid, roleid"; 00675 00676 $DB->execute($sql); 00677 00678 00680 $sql = "INSERT INTO {stats_weekly} (stattype, timeend, courseid, roleid, stat1, stat2) 00681 00682 SELECT 'activity', ntimeend, courseid, roleid, SUM(stat1), SUM(stat2) 00683 FROM ( 00684 SELECT $nextstartweek AS ntimeend, courseid, roleid, stat1, stat2 00685 FROM {stats_daily} 00686 WHERE stattype = 'activity' AND $stattimesql 00687 ) inline_view 00688 GROUP BY ntimeend, courseid, roleid"; 00689 00690 $DB->execute($sql); 00691 00692 00694 $sql = "INSERT INTO {stats_user_weekly} (stattype, timeend, courseid, userid, statsreads, statswrites) 00695 00696 SELECT 'activity', ntimeend, courseid, userid, SUM(statsreads), SUM(statswrites) 00697 FROM ( 00698 SELECT $nextstartweek AS ntimeend, courseid, userid, statsreads, statswrites 00699 FROM {stats_user_daily} 00700 WHERE stattype = 'activity' AND $stattimesql 00701 ) inline_view 00702 GROUP BY ntimeend, courseid, userid"; 00703 00704 $DB->execute($sql); 00705 00706 set_config('statslastweekly', $nextstartweek); 00707 mtrace(" finished until $nextstartweek: ".userdate($nextstartweek)); 00708 00709 $timestart = $nextstartweek; 00710 $nextstartweek = stats_get_next_week_start($nextstartweek); 00711 } 00712 00713 set_cron_lock('statsrunning', null); 00714 mtrace("...completed $weeks weeks of statistics."); 00715 return true; 00716 } 00717 00722 function stats_cron_monthly() { 00723 global $CFG, $DB; 00724 00725 $now = time(); 00726 00727 // read last execution date from db 00728 if (!$timestart = get_config(NULL, 'statslastmonthly')) { 00729 $timestart = stats_get_base_monthly(stats_get_start_from('monthly')); 00730 set_config('statslastmonthly', $timestart); 00731 } 00732 00733 $nextstartmonth = stats_get_next_month_start($timestart); 00734 00735 // are there any months that need to be processed? 00736 if ($now < $nextstartmonth) { 00737 return true; // everything ok and up-to-date 00738 } 00739 00740 $timeout = empty($CFG->statsmaxruntime) ? 60*60*24 : $CFG->statsmaxruntime; 00741 00742 if (!set_cron_lock('statsrunning', $now + $timeout)) { 00743 return false; 00744 } 00745 00746 // fisr delete entries that should not be there yet 00747 $DB->delete_records_select('stats_monthly', "timeend > $timestart"); 00748 $DB->delete_records_select('stats_user_monthly', "timeend > $timestart"); 00749 00750 $startmonth = stats_get_base_monthly($now); 00751 00752 00753 mtrace("Running monthly statistics gathering, starting at $timestart:"); 00754 00755 $months = 0; 00756 while ($now > $nextstartmonth) { 00757 @set_time_limit($timeout - 200); 00758 $months++; 00759 00760 if ($months > 1) { 00761 // move the lock 00762 set_cron_lock('statsrunning', time() + $timeout, true); 00763 } 00764 00765 $logtimesql = "l.time >= $timestart AND l.time < $nextstartmonth"; 00766 $stattimesql = "timeend > $timestart AND timeend <= $nextstartmonth"; 00767 00769 $sql = "INSERT INTO {stats_user_monthly} (stattype, timeend, courseid, userid, statsreads) 00770 00771 SELECT 'logins', timeend, courseid, userid, COUNT(statsreads) 00772 FROM ( 00773 SELECT $nextstartmonth AS timeend, ".SITEID." as courseid, l.userid, l.id AS statsreads 00774 FROM {log} l 00775 WHERE action = 'login' AND $logtimesql 00776 ) inline_view 00777 GROUP BY timeend, courseid, userid"; 00778 00779 $DB->execute($sql); 00780 00781 $sql = "INSERT INTO {stats_monthly} (stattype, timeend, courseid, roleid, stat1, stat2) 00782 00783 SELECT 'logins' AS stattype, $nextstartmonth AS timeend, ".SITEID." as courseid, 0, 00784 COALESCE((SELECT SUM(statsreads) 00785 FROM {stats_user_monthly} s1 00786 WHERE s1.stattype = 'logins' AND timeend = $nextstartmonth), 0) AS nstat1, 00787 (SELECT COUNT('x') 00788 FROM {stats_user_monthly} s2 00789 WHERE s2.stattype = 'logins' AND timeend = $nextstartmonth) AS nstat2" . 00790 $DB->sql_null_from_clause(); 00791 00792 $DB->execute($sql); 00793 00794 00796 $sql = "INSERT INTO {stats_monthly} (stattype, timeend, courseid, roleid, stat1, stat2) 00797 00798 SELECT 'enrolments', ntimeend, courseid, roleid, " . $DB->sql_ceil('AVG(stat1)') . ", " . $DB->sql_ceil('AVG(stat2)') . " 00799 FROM ( 00800 SELECT $nextstartmonth AS ntimeend, courseid, roleid, stat1, stat2 00801 FROM {stats_daily} sd 00802 WHERE stattype = 'enrolments' AND $stattimesql 00803 ) inline_view 00804 GROUP BY ntimeend, courseid, roleid"; 00805 00806 $DB->execute($sql); 00807 00808 00810 $sql = "INSERT INTO {stats_monthly} (stattype, timeend, courseid, roleid, stat1, stat2) 00811 00812 SELECT 'activity', ntimeend, courseid, roleid, SUM(stat1), SUM(stat2) 00813 FROM ( 00814 SELECT $nextstartmonth AS ntimeend, courseid, roleid, stat1, stat2 00815 FROM {stats_daily} 00816 WHERE stattype = 'activity' AND $stattimesql 00817 ) inline_view 00818 GROUP BY ntimeend, courseid, roleid"; 00819 00820 $DB->execute($sql); 00821 00822 00824 $sql = "INSERT INTO {stats_user_monthly} (stattype, timeend, courseid, userid, statsreads, statswrites) 00825 00826 SELECT 'activity', ntimeend, courseid, userid, SUM(statsreads), SUM(statswrites) 00827 FROM ( 00828 SELECT $nextstartmonth AS ntimeend, courseid, userid, statsreads, statswrites 00829 FROM {stats_user_daily} 00830 WHERE stattype = 'activity' AND $stattimesql 00831 ) inline_view 00832 GROUP BY ntimeend, courseid, userid"; 00833 00834 $DB->execute($sql); 00835 00836 set_config('statslastmonthly', $nextstartmonth); 00837 mtrace(" finished until $nextstartmonth: ".userdate($nextstartmonth)); 00838 00839 $timestart = $nextstartmonth; 00840 $nextstartmonth = stats_get_next_month_start($nextstartmonth); 00841 } 00842 00843 set_cron_lock('statsrunning', null); 00844 mtrace("...completed $months months of statistics."); 00845 return true; 00846 } 00847 00853 function stats_get_start_from($str) { 00854 global $CFG, $DB; 00855 00856 // are there any data in stats table? Should not be... 00857 if ($timeend = $DB->get_field_sql('SELECT MAX(timeend) FROM {stats_'.$str.'}')) { 00858 return $timeend; 00859 } 00860 // decide what to do based on our config setting (either all or none or a timestamp) 00861 switch ($CFG->statsfirstrun) { 00862 case 'all': 00863 if ($firstlog = $DB->get_field_sql('SELECT MIN(time) FROM {log}')) { 00864 return $firstlog; 00865 } 00866 default: 00867 if (is_numeric($CFG->statsfirstrun)) { 00868 return time() - $CFG->statsfirstrun; 00869 } 00870 // not a number? use next instead 00871 case 'none': 00872 return strtotime('-3 day', time()); 00873 } 00874 } 00875 00881 function stats_get_base_daily($time=0) { 00882 global $CFG; 00883 00884 if (empty($time)) { 00885 $time = time(); 00886 } 00887 if ($CFG->timezone == 99) { 00888 $time = strtotime(date('d-M-Y', $time)); 00889 return $time; 00890 } else { 00891 $offset = get_timezone_offset($CFG->timezone); 00892 $gtime = $time + $offset; 00893 $gtime = intval($gtime / (60*60*24)) * 60*60*24; 00894 return $gtime - $offset; 00895 } 00896 } 00897 00903 function stats_get_base_weekly($time=0) { 00904 global $CFG; 00905 00906 $time = stats_get_base_daily($time); 00907 $startday = $CFG->calendar_startwday; 00908 if ($CFG->timezone == 99) { 00909 $thisday = date('w', $time); 00910 } else { 00911 $offset = get_timezone_offset($CFG->timezone); 00912 $gtime = $time + $offset; 00913 $thisday = gmdate('w', $gtime); 00914 } 00915 if ($thisday > $startday) { 00916 $time = $time - (($thisday - $startday) * 60*60*24); 00917 } else if ($thisday < $startday) { 00918 $time = $time - ((7 + $thisday - $startday) * 60*60*24); 00919 } 00920 return $time; 00921 } 00922 00928 function stats_get_base_monthly($time=0) { 00929 global $CFG; 00930 00931 if (empty($time)) { 00932 $time = time(); 00933 } 00934 if ($CFG->timezone == 99) { 00935 return strtotime(date('1-M-Y', $time)); 00936 00937 } else { 00938 $time = stats_get_base_daily($time); 00939 $offset = get_timezone_offset($CFG->timezone); 00940 $gtime = $time + $offset; 00941 $day = gmdate('d', $gtime); 00942 if ($day == 1) { 00943 return $time; 00944 } 00945 return $gtime - (($day-1) * 60*60*24); 00946 } 00947 } 00948 00954 function stats_get_next_day_start($time) { 00955 $next = stats_get_base_daily($time); 00956 $next = $next + 60*60*26; 00957 $next = stats_get_base_daily($next); 00958 if ($next <= $time) { 00959 //DST trouble - prevent infinite loops 00960 $next = $next + 60*60*24; 00961 } 00962 return $next; 00963 } 00964 00970 function stats_get_next_week_start($time) { 00971 $next = stats_get_base_weekly($time); 00972 $next = $next + 60*60*24*9; 00973 $next = stats_get_base_weekly($next); 00974 if ($next <= $time) { 00975 //DST trouble - prevent infinite loops 00976 $next = $next + 60*60*24*7; 00977 } 00978 return $next; 00979 } 00980 00986 function stats_get_next_month_start($time) { 00987 $next = stats_get_base_monthly($time); 00988 $next = $next + 60*60*24*33; 00989 $next = stats_get_base_monthly($next); 00990 if ($next <= $time) { 00991 //DST trouble - prevent infinite loops 00992 $next = $next + 60*60*24*31; 00993 } 00994 return $next; 00995 } 00996 01000 function stats_clean_old() { 01001 global $DB; 01002 mtrace("Running stats cleanup tasks..."); 01003 $deletebefore = stats_get_base_monthly(); 01004 01005 // delete dailies older than 3 months (to be safe) 01006 $deletebefore = strtotime('-3 months', $deletebefore); 01007 $DB->delete_records_select('stats_daily', "timeend < $deletebefore"); 01008 $DB->delete_records_select('stats_user_daily', "timeend < $deletebefore"); 01009 01010 // delete weeklies older than 9 months (to be safe) 01011 $deletebefore = strtotime('-6 months', $deletebefore); 01012 $DB->delete_records_select('stats_weekly', "timeend < $deletebefore"); 01013 $DB->delete_records_select('stats_user_weekly', "timeend < $deletebefore"); 01014 01015 // don't delete monthlies 01016 01017 mtrace("...stats cleanup finished"); 01018 } 01019 01020 function stats_get_parameters($time,$report,$courseid,$mode,$roleid=0) { 01021 global $CFG, $DB; 01022 01023 $param = new stdClass(); 01024 $param->params = array(); 01025 01026 if ($time < 10) { // dailies 01027 // number of days to go back = 7* time 01028 $param->table = 'daily'; 01029 $param->timeafter = strtotime("-".($time*7)." days",stats_get_base_daily()); 01030 } elseif ($time < 20) { // weeklies 01031 // number of weeks to go back = time - 10 * 4 (weeks) + base week 01032 $param->table = 'weekly'; 01033 $param->timeafter = strtotime("-".(($time - 10)*4)." weeks",stats_get_base_weekly()); 01034 } else { // monthlies. 01035 // number of months to go back = time - 20 * months + base month 01036 $param->table = 'monthly'; 01037 $param->timeafter = strtotime("-".($time - 20)." months",stats_get_base_monthly()); 01038 } 01039 01040 $param->extras = ''; 01041 01042 switch ($report) { 01043 // ******************** STATS_MODE_GENERAL ******************** // 01044 case STATS_REPORT_LOGINS: 01045 $param->fields = 'timeend,sum(stat1) as line1,sum(stat2) as line2'; 01046 $param->fieldscomplete = true; 01047 $param->stattype = 'logins'; 01048 $param->line1 = get_string('statslogins'); 01049 $param->line2 = get_string('statsuniquelogins'); 01050 if ($courseid == SITEID) { 01051 $param->extras = 'GROUP BY timeend'; 01052 } 01053 break; 01054 01055 case STATS_REPORT_READS: 01056 $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, stat1 as line1'; 01057 $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries. 01058 $param->aggregategroupby = 'roleid'; 01059 $param->stattype = 'activity'; 01060 $param->crosstab = true; 01061 $param->extras = 'GROUP BY timeend,roleid,stat1'; 01062 if ($courseid == SITEID) { 01063 $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, sum(stat1) as line1'; 01064 $param->extras = 'GROUP BY timeend,roleid'; 01065 } 01066 break; 01067 01068 case STATS_REPORT_WRITES: 01069 $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, stat2 as line1'; 01070 $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries. 01071 $param->aggregategroupby = 'roleid'; 01072 $param->stattype = 'activity'; 01073 $param->crosstab = true; 01074 $param->extras = 'GROUP BY timeend,roleid,stat2'; 01075 if ($courseid == SITEID) { 01076 $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, sum(stat2) as line1'; 01077 $param->extras = 'GROUP BY timeend,roleid'; 01078 } 01079 break; 01080 01081 case STATS_REPORT_ACTIVITY: 01082 $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, sum(stat1+stat2) as line1'; 01083 $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries. 01084 $param->aggregategroupby = 'roleid'; 01085 $param->stattype = 'activity'; 01086 $param->crosstab = true; 01087 $param->extras = 'GROUP BY timeend,roleid'; 01088 if ($courseid == SITEID) { 01089 $param->extras = 'GROUP BY timeend,roleid'; 01090 } 01091 break; 01092 01093 case STATS_REPORT_ACTIVITYBYROLE; 01094 $param->fields = 'stat1 AS line1, stat2 AS line2'; 01095 $param->stattype = 'activity'; 01096 $rolename = $DB->get_field('role','name', array('id'=>$roleid)); 01097 $param->line1 = $rolename . get_string('statsreads'); 01098 $param->line2 = $rolename . get_string('statswrites'); 01099 if ($courseid == SITEID) { 01100 $param->extras = 'GROUP BY timeend'; 01101 } 01102 break; 01103 01104 // ******************** STATS_MODE_DETAILED ******************** // 01105 case STATS_REPORT_USER_ACTIVITY: 01106 $param->fields = 'statsreads as line1, statswrites as line2'; 01107 $param->line1 = get_string('statsuserreads'); 01108 $param->line2 = get_string('statsuserwrites'); 01109 $param->stattype = 'activity'; 01110 break; 01111 01112 case STATS_REPORT_USER_ALLACTIVITY: 01113 $param->fields = 'statsreads+statswrites as line1'; 01114 $param->line1 = get_string('statsuseractivity'); 01115 $param->stattype = 'activity'; 01116 break; 01117 01118 case STATS_REPORT_USER_LOGINS: 01119 $param->fields = 'statsreads as line1'; 01120 $param->line1 = get_string('statsuserlogins'); 01121 $param->stattype = 'logins'; 01122 break; 01123 01124 case STATS_REPORT_USER_VIEW: 01125 $param->fields = 'statsreads as line1, statswrites as line2, statsreads+statswrites as line3'; 01126 $param->line1 = get_string('statsuserreads'); 01127 $param->line2 = get_string('statsuserwrites'); 01128 $param->line3 = get_string('statsuseractivity'); 01129 $param->stattype = 'activity'; 01130 break; 01131 01132 // ******************** STATS_MODE_RANKED ******************** // 01133 case STATS_REPORT_ACTIVE_COURSES: 01134 $param->fields = 'sum(stat1+stat2) AS line1'; 01135 $param->stattype = 'activity'; 01136 $param->orderby = 'line1 DESC'; 01137 $param->line1 = get_string('activity'); 01138 $param->graphline = 'line1'; 01139 break; 01140 01141 case STATS_REPORT_ACTIVE_COURSES_WEIGHTED: 01142 $threshold = 0; 01143 if (!empty($CFG->statsuserthreshold) && is_numeric($CFG->statsuserthreshold)) { 01144 $threshold = $CFG->statsuserthreshold; 01145 } 01146 $param->fields = ''; 01147 $param->sql = 'SELECT activity.courseid, activity.all_activity AS line1, enrolments.highest_enrolments AS line2, 01148 activity.all_activity / enrolments.highest_enrolments as line3 01149 FROM ( 01150 SELECT courseid, sum(stat1+stat2) AS all_activity 01151 FROM {stats_'.$param->table.'} 01152 WHERE stattype=\'activity\' AND timeend >= '.(int)$param->timeafter.' AND roleid = 0 GROUP BY courseid 01153 ) activity 01154 INNER JOIN 01155 ( 01156 SELECT courseid, max(stat1) AS highest_enrolments 01157 FROM {stats_'.$param->table.'} 01158 WHERE stattype=\'enrolments\' AND timeend >= '.(int)$param->timeafter.' AND stat1 > '.(int)$threshold.' 01159 GROUP BY courseid 01160 ) enrolments 01161 ON (activity.courseid = enrolments.courseid) 01162 ORDER BY line3 DESC'; 01163 $param->line1 = get_string('activity'); 01164 $param->line2 = get_string('users'); 01165 $param->line3 = get_string('activityweighted'); 01166 $param->graphline = 'line3'; 01167 break; 01168 01169 case STATS_REPORT_PARTICIPATORY_COURSES: 01170 $threshold = 0; 01171 if (!empty($CFG->statsuserthreshold) && is_numeric($CFG->statsuserthreshold)) { 01172 $threshold = $CFG->statsuserthreshold; 01173 } 01174 $param->fields = ''; 01175 $param->sql = 'SELECT courseid, ' . $DB->sql_ceil('avg(all_enrolments)') . ' as line1, ' . 01176 $DB->sql_ceil('avg(active_enrolments)') . ' as line2, avg(proportion_active) AS line3 01177 FROM ( 01178 SELECT courseid, timeend, stat2 as active_enrolments, 01179 stat1 as all_enrolments, '.$DB->sql_cast_char2real('stat2').'/'.$DB->sql_cast_char2real('stat1').' AS proportion_active 01180 FROM {stats_'.$param->table.'} 01181 WHERE stattype=\'enrolments\' AND roleid = 0 AND stat1 > '.(int)$threshold.' 01182 ) aq 01183 WHERE timeend >= '.(int)$param->timeafter.' 01184 GROUP BY courseid 01185 ORDER BY line3 DESC'; 01186 01187 $param->line1 = get_string('users'); 01188 $param->line2 = get_string('activeusers'); 01189 $param->line3 = get_string('participationratio'); 01190 $param->graphline = 'line3'; 01191 break; 01192 01193 case STATS_REPORT_PARTICIPATORY_COURSES_RW: 01194 $param->fields = ''; 01195 $param->sql = 'SELECT courseid, sum(views) AS line1, sum(posts) AS line2, 01196 avg(proportion_active) AS line3 01197 FROM ( 01198 SELECT courseid, timeend, stat1 as views, stat2 AS posts, 01199 '.$DB->sql_cast_char2real('stat2').'/'.$DB->sql_cast_char2real('stat1').' as proportion_active 01200 FROM {stats_'.$param->table.'} 01201 WHERE stattype=\'activity\' AND roleid = 0 AND stat1 > 0 01202 ) aq 01203 WHERE timeend >= '.(int)$param->timeafter.' 01204 GROUP BY courseid 01205 ORDER BY line3 DESC'; 01206 $param->line1 = get_string('views'); 01207 $param->line2 = get_string('posts'); 01208 $param->line3 = get_string('participationratio'); 01209 $param->graphline = 'line3'; 01210 break; 01211 } 01212 01213 /* 01214 if ($courseid == SITEID && $mode != STATS_MODE_RANKED) { // just aggregate all courses. 01215 $param->fields = preg_replace('/(?:sum)([a-zA-Z0-9+_]*)\W+as\W+([a-zA-Z0-9_]*)/i','sum($1) as $2',$param->fields); 01216 $param->extras = ' GROUP BY timeend'.((!empty($param->aggregategroupby)) ? ','.$param->aggregategroupby : ''); 01217 } 01218 */ 01219 //TODO must add the SITEID reports to the rest of the reports. 01220 return $param; 01221 } 01222 01223 function stats_get_view_actions() { 01224 return array('view','view all','history'); 01225 } 01226 01227 function stats_get_post_actions() { 01228 return array('add','delete','edit','add mod','delete mod','edit section'.'enrol','loginas','new','unenrol','update','update mod'); 01229 } 01230 01231 function stats_get_action_names($str) { 01232 global $CFG, $DB; 01233 01234 $mods = $DB->get_records('modules'); 01235 $function = 'stats_get_'.$str.'_actions'; 01236 $actions = $function(); 01237 foreach ($mods as $mod) { 01238 $file = $CFG->dirroot.'/mod/'.$mod->name.'/lib.php'; 01239 if (!is_readable($file)) { 01240 continue; 01241 } 01242 require_once($file); 01243 $function = $mod->name.'_get_'.$str.'_actions'; 01244 if (function_exists($function)) { 01245 $mod_actions = $function(); 01246 if (is_array($mod_actions)) { 01247 $actions = array_merge($actions, $mod_actions); 01248 } 01249 } 01250 } 01251 01252 // The array_values() forces a stack-like array 01253 // so we can later loop over safely... 01254 $actions = array_values(array_unique($actions)); 01255 $c = count($actions); 01256 for ($n=0;$n<$c;$n++) { 01257 $actions[$n] = $actions[$n]; 01258 } 01259 return $actions; 01260 } 01261 01262 function stats_get_time_options($now,$lastweekend,$lastmonthend,$earliestday,$earliestweek,$earliestmonth) { 01263 01264 $now = stats_get_base_daily(time()); 01265 // it's really important that it's TIMEEND in the table. ie, tuesday 00:00:00 is monday night. 01266 // so we need to take a day off here (essentially add a day to $now 01267 $now += 60*60*24; 01268 01269 $timeoptions = array(); 01270 01271 if ($now - (60*60*24*7) >= $earliestday) { 01272 $timeoptions[STATS_TIME_LASTWEEK] = get_string('numweeks','moodle',1); 01273 } 01274 if ($now - (60*60*24*14) >= $earliestday) { 01275 $timeoptions[STATS_TIME_LAST2WEEKS] = get_string('numweeks','moodle',2); 01276 } 01277 if ($now - (60*60*24*21) >= $earliestday) { 01278 $timeoptions[STATS_TIME_LAST3WEEKS] = get_string('numweeks','moodle',3); 01279 } 01280 if ($now - (60*60*24*28) >= $earliestday) { 01281 $timeoptions[STATS_TIME_LAST4WEEKS] = get_string('numweeks','moodle',4);// show dailies up to (including) here. 01282 } 01283 if ($lastweekend - (60*60*24*56) >= $earliestweek) { 01284 $timeoptions[STATS_TIME_LAST2MONTHS] = get_string('nummonths','moodle',2); 01285 } 01286 if ($lastweekend - (60*60*24*84) >= $earliestweek) { 01287 $timeoptions[STATS_TIME_LAST3MONTHS] = get_string('nummonths','moodle',3); 01288 } 01289 if ($lastweekend - (60*60*24*112) >= $earliestweek) { 01290 $timeoptions[STATS_TIME_LAST4MONTHS] = get_string('nummonths','moodle',4); 01291 } 01292 if ($lastweekend - (60*60*24*140) >= $earliestweek) { 01293 $timeoptions[STATS_TIME_LAST5MONTHS] = get_string('nummonths','moodle',5); 01294 } 01295 if ($lastweekend - (60*60*24*168) >= $earliestweek) { 01296 $timeoptions[STATS_TIME_LAST6MONTHS] = get_string('nummonths','moodle',6); // show weeklies up to (including) here 01297 } 01298 if (strtotime('-7 months',$lastmonthend) >= $earliestmonth) { 01299 $timeoptions[STATS_TIME_LAST7MONTHS] = get_string('nummonths','moodle',7); 01300 } 01301 if (strtotime('-8 months',$lastmonthend) >= $earliestmonth) { 01302 $timeoptions[STATS_TIME_LAST8MONTHS] = get_string('nummonths','moodle',8); 01303 } 01304 if (strtotime('-9 months',$lastmonthend) >= $earliestmonth) { 01305 $timeoptions[STATS_TIME_LAST9MONTHS] = get_string('nummonths','moodle',9); 01306 } 01307 if (strtotime('-10 months',$lastmonthend) >= $earliestmonth) { 01308 $timeoptions[STATS_TIME_LAST10MONTHS] = get_string('nummonths','moodle',10); 01309 } 01310 if (strtotime('-11 months',$lastmonthend) >= $earliestmonth) { 01311 $timeoptions[STATS_TIME_LAST11MONTHS] = get_string('nummonths','moodle',11); 01312 } 01313 if (strtotime('-1 year',$lastmonthend) >= $earliestmonth) { 01314 $timeoptions[STATS_TIME_LASTYEAR] = get_string('lastyear'); 01315 } 01316 01317 $years = (int)date('y', $now) - (int)date('y', $earliestmonth); 01318 if ($years > 1) { 01319 for($i = 2; $i <= $years; $i++) { 01320 $timeoptions[$i*12+20] = get_string('numyears', 'moodle', $i); 01321 } 01322 } 01323 01324 return $timeoptions; 01325 } 01326 01327 function stats_get_report_options($courseid,$mode) { 01328 global $CFG, $DB; 01329 01330 $reportoptions = array(); 01331 01332 switch ($mode) { 01333 case STATS_MODE_GENERAL: 01334 $reportoptions[STATS_REPORT_ACTIVITY] = get_string('statsreport'.STATS_REPORT_ACTIVITY); 01335 if ($courseid != SITEID && $context = get_context_instance(CONTEXT_COURSE, $courseid)) { 01336 $sql = 'SELECT r.id, r.name FROM {role} r JOIN {stats_daily} s ON s.roleid = r.id WHERE s.courseid = :courseid GROUP BY r.id, r.name'; 01337 if ($roles = $DB->get_records_sql($sql, array('courseid' => $courseid))) { 01338 foreach ($roles as $role) { 01339 $reportoptions[STATS_REPORT_ACTIVITYBYROLE.$role->id] = get_string('statsreport'.STATS_REPORT_ACTIVITYBYROLE). ' '.$role->name; 01340 } 01341 } 01342 } 01343 $reportoptions[STATS_REPORT_READS] = get_string('statsreport'.STATS_REPORT_READS); 01344 $reportoptions[STATS_REPORT_WRITES] = get_string('statsreport'.STATS_REPORT_WRITES); 01345 if ($courseid == SITEID) { 01346 $reportoptions[STATS_REPORT_LOGINS] = get_string('statsreport'.STATS_REPORT_LOGINS); 01347 } 01348 01349 break; 01350 case STATS_MODE_DETAILED: 01351 $reportoptions[STATS_REPORT_USER_ACTIVITY] = get_string('statsreport'.STATS_REPORT_USER_ACTIVITY); 01352 $reportoptions[STATS_REPORT_USER_ALLACTIVITY] = get_string('statsreport'.STATS_REPORT_USER_ALLACTIVITY); 01353 if (has_capability('report/stats:view', get_context_instance(CONTEXT_SYSTEM))) { 01354 $site = get_site(); 01355 $reportoptions[STATS_REPORT_USER_LOGINS] = get_string('statsreport'.STATS_REPORT_USER_LOGINS); 01356 } 01357 break; 01358 case STATS_MODE_RANKED: 01359 if (has_capability('report/stats:view', get_context_instance(CONTEXT_SYSTEM))) { 01360 $reportoptions[STATS_REPORT_ACTIVE_COURSES] = get_string('statsreport'.STATS_REPORT_ACTIVE_COURSES); 01361 $reportoptions[STATS_REPORT_ACTIVE_COURSES_WEIGHTED] = get_string('statsreport'.STATS_REPORT_ACTIVE_COURSES_WEIGHTED); 01362 $reportoptions[STATS_REPORT_PARTICIPATORY_COURSES] = get_string('statsreport'.STATS_REPORT_PARTICIPATORY_COURSES); 01363 $reportoptions[STATS_REPORT_PARTICIPATORY_COURSES_RW] = get_string('statsreport'.STATS_REPORT_PARTICIPATORY_COURSES_RW); 01364 } 01365 break; 01366 } 01367 01368 return $reportoptions; 01369 } 01370 01371 function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) { 01372 01373 if (empty($stats)) { 01374 return; 01375 } 01376 01377 $timestr = str_replace('user_','',$timestr); // just in case. 01378 $fun = 'stats_get_base_'.$timestr; 01379 01380 $now = $fun(); 01381 01382 $times = array(); 01383 // add something to timeafter since it is our absolute base 01384 $actualtimes = array(); 01385 foreach ($stats as $statid=>$s) { 01386 //normalize the times in stats - those might have been created in different timezone, DST etc. 01387 $s->timeend = $fun($s->timeend + 60*60*5); 01388 $stats[$statid] = $s; 01389 01390 $actualtimes[] = $s->timeend; 01391 } 01392 01393 $timeafter = array_pop(array_values($actualtimes)); 01394 01395 while ($timeafter < $now) { 01396 $times[] = $timeafter; 01397 if ($timestr == 'daily') { 01398 $timeafter = stats_get_next_day_start($timeafter); 01399 } else if ($timestr == 'weekly') { 01400 $timeafter = stats_get_next_week_start($timeafter); 01401 } else if ($timestr == 'monthly') { 01402 $timeafter = stats_get_next_month_start($timeafter); 01403 } else { 01404 return $stats; // this will put us in a never ending loop. 01405 } 01406 } 01407 01408 foreach ($times as $count => $time) { 01409 if (!in_array($time,$actualtimes) && $count != count($times) -1) { 01410 $newobj = new StdClass; 01411 $newobj->timeend = $time; 01412 $newobj->id = 0; 01413 $newobj->roleid = 0; 01414 $newobj->line1 = 0; 01415 if (!empty($line2)) { 01416 $newobj->line2 = 0; 01417 } 01418 if (!empty($line3)) { 01419 $newobj->line3 = 0; 01420 } 01421 $newobj->zerofixed = true; 01422 $stats[] = $newobj; 01423 } 01424 } 01425 01426 usort($stats,"stats_compare_times"); 01427 return $stats; 01428 01429 } 01430 01431 // helper function to sort arrays by $obj->timeend 01432 function stats_compare_times($a,$b) { 01433 if ($a->timeend == $b->timeend) { 01434 return 0; 01435 } 01436 return ($a->timeend > $b->timeend) ? -1 : 1; 01437 } 01438 01439 function stats_check_uptodate($courseid=0) { 01440 global $CFG, $DB; 01441 01442 if (empty($courseid)) { 01443 $courseid = SITEID; 01444 } 01445 01446 $latestday = stats_get_start_from('daily'); 01447 01448 if ((time() - 60*60*24*2) < $latestday) { // we're ok 01449 return NULL; 01450 } 01451 01452 $a = new stdClass(); 01453 $a->daysdone = $DB->get_field_sql("SELECT COUNT(DISTINCT(timeend)) FROM {stats_daily}"); 01454 01455 // how many days between the last day and now? 01456 $a->dayspending = ceil((stats_get_base_daily() - $latestday)/(60*60*24)); 01457 01458 if ($a->dayspending == 0 && $a->daysdone != 0) { 01459 return NULL; // we've only just started... 01460 } 01461 01462 //return error as string 01463 return get_string('statscatchupmode','error',$a); 01464 }