3 // THESE CONSTANTS ARE USED FOR THE REPORTING PAGE.
5 define('STATS_REPORT_LOGINS',1); // double impose logins and unqiue logins on a line graph. site course only.
6 define('STATS_REPORT_READS',2); // double impose student reads and teacher reads on a line graph.
7 define('STATS_REPORT_WRITES',3); // double impose student writes and teacher writes on a line graph.
8 define('STATS_REPORT_ACTIVITY',4); // 2+3 added up, teacher vs student.
9 define('STATS_REPORT_STUDENTACTIVITY',5); // all student activity, reads vs writes
10 define('STATS_REPORT_TEACHERACTIVITY',6); // all teacher activity, reads vs writes
12 // user level stats reports.
13 define('STATS_REPORT_USER_ACTIVITY',7);
14 define('STATS_REPORT_USER_ALLACTIVITY',8);
15 define('STATS_REPORT_USER_LOGINS',9);
16 define('STATS_REPORT_USER_VIEW',10); // this is the report you see on the user profile.
18 // admin only ranking stats reports
19 define('STATS_REPORT_ACTIVE_COURSES',11);
20 define('STATS_REPORT_ACTIVE_COURSES_WEIGHTED',12);
21 define('STATS_REPORT_PARTICIPATORY_COURSES',13);
22 define('STATS_REPORT_PARTICIPATORY_COURSES_RW',14);
24 // start after 0 = show dailies.
25 define('STATS_TIME_LASTWEEK',1);
26 define('STATS_TIME_LAST2WEEKS',2);
27 define('STATS_TIME_LAST3WEEKS',3);
28 define('STATS_TIME_LAST4WEEKS',4);
30 // start after 10 = show weeklies
31 define('STATS_TIME_LAST2MONTHS',12);
33 define('STATS_TIME_LAST3MONTHS',13);
34 define('STATS_TIME_LAST4MONTHS',14);
35 define('STATS_TIME_LAST5MONTHS',15);
36 define('STATS_TIME_LAST6MONTHS',16);
38 // start after 20 = show monthlies
39 define('STATS_TIME_LAST7MONTHS',27);
40 define('STATS_TIME_LAST8MONTHS',28);
41 define('STATS_TIME_LAST9MONTHS',29);
42 define('STATS_TIME_LAST10MONTHS',30);
43 define('STATS_TIME_LAST11MONTHS',31);
44 define('STATS_TIME_LASTYEAR',32);
46 // different modes for what reports to offer
47 define('STATS_MODE_GENERAL',1);
48 define('STATS_MODE_DETAILED',2);
49 define('STATS_MODE_RANKED',3); // admins only - ranks courses
51 // return codes - whether to rerun
52 define('STATS_RUN_COMPLETE',1);
53 define('STATS_RUN_ABORTED',0);
55 function stats_cron_daily () {
58 if (empty($CFG->enablestats
)) {
59 return STATS_RUN_ABORTED
;
62 if (!$timestart = stats_get_start_from('daily')) {
63 return STATS_RUN_ABORTED
;
67 $midnight = stats_getmidnight(time());
69 // check to make sure we're due to run, at least one day after last run
70 if (isset($CFG->statslastdaily
) and ((time() - 24*60*60) < $CFG->statslastdaily
)) {
71 return STATS_RUN_ABORTED
;
74 mtrace("Running daily statistics gathering...");
75 set_config('statslastdaily',time());
77 $return = STATS_RUN_COMPLETE
; // optimistic
79 static $daily_modules;
81 if (empty($daily_modules)) {
82 $daily_modules = array();
83 $mods = get_records("modules");
84 foreach ($mods as $mod) {
85 require_once($CFG->dirroot
.'/mod/'.$mod->name
.'/lib.php');
86 $fname = $mod->name
.'_get_daily_stats';
87 if (function_exists($fname)) {
88 $daily_modules[$mod] = $fname;
93 $nextmidnight = stats_get_next_dayend($timestart);
95 if (!$courses = get_records('course','','','','id,1')) {
96 return STATS_RUN_ABORTED
;
100 mtrace("starting at $timestart");
101 while ($midnight > $nextmidnight && $timestart < $nextmidnight) {
103 $timesql = " (l.time > $timestart AND l.time < $nextmidnight) ";
105 foreach ($courses as $course) {
107 $stat->students
= count_records('user_students','course',$course->id
);
108 $stat->teachers
= count_records('user_teachers','course',$course->id
);
110 $sql = 'SELECT COUNT(DISTINCT(l.userid)) FROM '.$CFG->prefix
.'log l JOIN '.$CFG->prefix
111 .'user_students us ON us.userid = l.userid WHERE l.course = '.$course->id
.' AND us.course = '.$course->id
.' AND '.$timesql;
112 $stat->activestudents
= count_records_sql($sql);
114 $sql = str_replace('students','teachers',$sql);
115 $stat->activeteachers
= count_records_sql($sql);
117 $sql = 'SELECT COUNT(l.id) FROM '.$CFG->prefix
.'log l JOIN '.$CFG->prefix
118 .'user_students us ON us.userid = l.userid WHERE l.course = '.$course->id
.' AND us.course = '.$course->id
119 .' AND '.$timesql .' '.stats_get_action_sql_in('view');
120 $stat->studentreads
= count_records_sql($sql);
122 $sql = str_replace('students','teachers',$sql);
123 $stat->teacherreads
= count_records_sql($sql);
125 $sql = 'SELECT COUNT(l.id) FROM '.$CFG->prefix
.'log l JOIN '.$CFG->prefix
126 .'user_students us ON us.userid = l.userid WHERE l.course = '.$course->id
.' AND us.course = '.$course->id
127 .' AND '.$timesql.' '.stats_get_action_sql_in('post');
128 $stat->studentwrites
= count_records_sql($sql);
130 $sql = str_replace('students','teachers',$sql);
131 $stat->teacherwrites
= count_records_sql($sql);
134 $stat->uniquelogins
= 0;
135 if ($course->id
== SITEID
) {
136 $sql = 'SELECT count(l.id) FROM '.$CFG->prefix
.'log l WHERE l.action = \'login\' AND '.$timesql;
137 $stat->logins
= count_records_sql($sql);
138 $sql = 'SELECT COUNT(DISTINCT(l.userid)) FROM '.$CFG->prefix
.'log l WHERE l.action = \'login\' AND '.$timesql;
139 $stat->uniquelogins
= count_records_sql($sql);
142 $stat->courseid
= $course->id
;
143 $stat->timeend
= $nextmidnight;
144 insert_record('stats_daily',$stat,false); // don't worry about the return id, we don't need it.
150 if ($course->id
== SITEID
) {
151 $sql = 'SELECT l.userid,count(l.id) as count FROM '.$CFG->prefix
.'log l WHERE action = \'login\' AND '.$timesql.' GROUP BY userid';
153 if ($logins = get_records_sql($sql)) {
154 foreach ($logins as $l) {
155 $stat->statsreads
= $l->count
;
156 $stat->userid
= $l->userid
;
157 $stat->timeend
= $nextmidnight;
158 $stat->courseid
= SITEID
;
159 $stat->statswrites
= 0;
160 $stat->stattype
= 'logins';
162 insert_record('stats_user_daily',$stat,false);
168 stats_get_course_users($course,$timesql,$students,$teachers);
170 foreach ($students as $user) {
171 stats_do_daily_user_cron($course,$user,1,$timesql,$nextmidnight,$daily_modules);
173 foreach ($teachers as $user) {
174 stats_do_daily_user_cron($course,$user,2,$timesql,$nextmidnight,$daily_modules);
178 $timestart = $nextmidnight;
179 $nextmidnight = stats_get_next_dayend($nextmidnight);
182 if (!stats_check_runtime()) {
183 mtrace("Stopping early! reached maxruntime");
184 $return = STATS_RUN_ABORTED
;
188 mtrace("got up to ".$timestart);
189 mtrace("Completed $days days");
195 function stats_cron_weekly () {
199 if (empty($CFG->enablestats
)) {
203 if (!$timestart = stats_get_start_from('weekly')) {
204 return STATS_RUN_ABORTED
;
207 // check to make sure we're due to run, at least one week after last run
208 $sunday = stats_get_base_weekly();
210 if (isset($CFG->statslastweekly
) and ((time() - (7*24*60*60)) <= $CFG->statslastweekly
)) {
211 return STATS_RUN_ABORTED
;
214 mtrace("Running weekly statistics gathering...");
215 set_config('statslastweekly',time());
217 $return = STATS_RUN_COMPLETE
; // optimistic
219 static $weekly_modules;
221 if (empty($weekly_modules)) {
222 $weekly_modules = array();
223 $mods = get_records("modules");
224 foreach ($mods as $mod) {
225 require_once($CFG->dirroot
.'/mod/'.$mod->name
.'/lib.php');
226 $fname = $mod->name
.'_get_weekly_stats';
227 if (function_exists($fname)) {
228 $weekly_modules[$mod] = $fname;
233 $nextsunday = stats_get_next_weekend($timestart);
235 if (!$courses = get_records('course','','','','id,1')) {
236 return STATS_RUN_ABORTED
;
240 mtrace("starting at $timestart");
241 while ($sunday > $nextsunday && $timestart < $nextsunday) {
243 $timesql = " (timeend > $timestart AND timeend < $nextsunday) ";
245 foreach ($courses as $course) {
247 $sql = 'SELECT ceil(avg(students)) as students, ceil(avg(teachers)) as teachers,
248 ceil(avg(activestudents)) as activestudents,ceil(avg(activeteachers)) as activeteachers,
249 sum(studentreads) as studentreads, sum(studentwrites) as studentwrites,
250 sum(teacherreads) as teacherreads, sum(teacherwrites) as teacherwrites,
251 sum(logins) as logins FROM '.$CFG->prefix
.'stats_daily WHERE courseid = '.$course->id
.' AND '.$timesql;
253 $stat = get_record_sql($sql);
255 $stat->uniquelogins
= 0;
256 if ($course->id
== SITEID
) {
257 $sql = 'SELECT COUNT(DISTINCT(l.userid)) FROM '.$CFG->prefix
.'log l WHERE l.action = \'login\' AND '
258 .str_replace('timeend','time',$timesql);
259 $stat->uniquelogins
= count_records_sql($sql);
262 $stat->courseid
= $course->id
;
263 $stat->timeend
= $nextsunday;
265 foreach (array_keys((array)$stat) as $key) {
266 if (!isset($stat->$key)) {
267 $stat->$key = 0; // we don't want nulls , so avoid them.
271 insert_record('stats_weekly',$stat,false); // don't worry about the return id, we don't need it.
276 stats_get_course_users($course,$timesql,$students,$teachers);
278 foreach ($students as $user) {
279 stats_do_aggregate_user_cron($course,$user,1,$timesql,$nextsunday,'weekly',$weekly_modules);
282 foreach ($teachers as $user) {
283 stats_do_aggregate_user_cron($course,$user,2,$timesql,$nextsunday,'weekly',$weekly_modules);
287 stats_do_aggregate_user_login_cron($timesql,$nextsunday,'weekly');
289 $timestart = $nextsunday;
290 $nextsunday = stats_get_next_weekend($nextsunday);
293 if (!stats_check_runtime()) {
294 mtrace("Stopping early! reached maxruntime");
295 $return = STATS_RUN_ABORTED
;
299 mtrace("got up to ".$timestart);
300 mtrace("Completed $weeks weeks");
305 function stats_cron_monthly () {
308 if (empty($CFG->enablestats
)) {
309 return STATS_RUN_ABORTED
;
312 if (!$timestart = stats_get_start_from('monthly')) {
313 return STATS_RUN_ABORTED
;
316 // check to make sure we're due to run, at least one month after last run
317 $monthend = stats_get_base_monthly();
319 if (isset($CFG->statslastmonthly
) and ((time() - (31*24*60*60)) <= $CFG->statslastmonthly
)) {
320 return STATS_RUN_ABORTED
;
323 mtrace("Running monthly statistics gathering...");
324 set_config('statslastmonthly',time());
326 $return = STATS_RUN_COMPLETE
; // optimistic
328 static $monthly_modules;
330 if (empty($monthly_modules)) {
331 $monthly_modules = array();
332 $mods = get_records("modules");
333 foreach ($mods as $mod) {
334 require_once($CFG->dirroot
.'/mod/'.$mod->name
.'/lib.php');
335 $fname = $mod->name
.'_get_monthly_stats';
336 if (function_exists($fname)) {
337 $monthly_modules[$mod] = $fname;
342 $nextmonthend = stats_get_next_monthend($timestart);
344 if (!$courses = get_records('course','','','','id,1')) {
345 return STATS_RUN_ABORTED
;
349 mtrace("starting from $timestart");
350 while ($monthend > $nextmonthend && $timestart < $nextmonthend) {
352 $timesql = " (timeend > $timestart AND timeend < $nextmonthend) ";
354 foreach ($courses as $course) {
356 $sql = 'SELECT ceil(avg(students)) as students, ceil(avg(teachers)) as teachers, ceil(avg(activestudents)) as activestudents,ceil(avg(activeteachers)) as activeteachers,
357 sum(studentreads) as studentreads, sum(studentwrites) as studentwrites, sum(teacherreads) as teacherreads, sum(teacherwrites) as teacherwrites,
358 sum(logins) as logins FROM '.$CFG->prefix
.'stats_daily WHERE courseid = '.$course->id
.' AND '.$timesql;
360 $stat = get_record_sql($sql);
362 $stat->uniquelogins
= 0;
363 if ($course->id
== SITEID
) {
364 $sql = 'SELECT COUNT(DISTINCT(l.userid)) FROM '.$CFG->prefix
.'log l WHERE l.action = \'login\' AND '.str_replace('timeend','time',$timesql);
365 $stat->uniquelogins
= count_records_sql($sql);
368 $stat->courseid
= $course->id
;
369 $stat->timeend
= $nextmonthend;
371 foreach (array_keys((array)$stat) as $key) {
372 if (!isset($stat->$key)) {
373 $stat->$key = 0; // we don't want nulls , so avoid them.
377 insert_record('stats_monthly',$stat,false); // don't worry about the return id, we don't need it.
382 stats_get_course_users($course,$timesql,$students,$teachers);
384 foreach ($students as $user) {
385 stats_do_aggregate_user_cron($course,$user,1,$timesql,$nextmonthend,'monthly',$monthly_modules);
388 foreach ($teachers as $user) {
389 stats_do_aggregate_user_cron($course,$user,2,$timesql,$nextmonthend,'monthly',$monthly_modules);
392 stats_do_aggregate_user_login_cron($timesql,$nextmonthend,'monthly');
394 $timestart = $nextmonthend;
395 $nextmonthend = stats_get_next_monthend($timestart);
397 if (!stats_check_runtime()) {
398 mtrace("Stopping early! reached maxruntime");
400 $return = STATS_RUN_ABORTED
;
403 mtrace("got up to $timestart");
404 mtrace("Completed $months months");
408 function stats_get_start_from($str) {
411 // if it's not our first run, just return the most recent.
412 if ($timeend = get_field_sql('SELECT timeend FROM '.$CFG->prefix
.'stats_'.$str.' ORDER BY timeend DESC LIMIT 1')) {
416 // decide what to do based on our config setting (either all or none or a timestamp)
417 $function = 'stats_get_base_'.$str;
418 switch ($CFG->statsfirstrun
) {
420 return $function(get_field_sql('SELECT time FROM '.$CFG->prefix
.'log ORDER BY time LIMIT 1'));
423 return $function(strtotime('-1 day',time()));
426 if (is_numeric($CFG->statsfirstrun
)) {
427 return $function(time() - $CFG->statsfirstrun
);
434 function stats_get_base_daily($time=0) {
438 return stats_getmidnight($time);
441 function stats_get_base_weekly($time=0) {
445 // if we're currently a monday, last monday will take us back a week
446 $str = 'last monday';
447 if (date('D',$time) == 'Mon')
450 return stats_getmidnight(strtotime($str,$time));
453 function stats_get_base_monthly($time=0) {
457 return stats_getmidnight(strtotime(date('1-M-Y',$time)));
460 function stats_get_next_monthend($lastmonth) {
461 return stats_getmidnight(strtotime(date('1-M-Y',$lastmonth).' +1 month'));
464 function stats_get_next_weekend($lastweek) {
465 return stats_getmidnight(strtotime('+1 week',$lastweek));
468 function stats_get_next_dayend($lastday) {
469 return stats_getmidnight(strtotime('+1 day',$lastday));
472 function stats_clean_old() {
473 mtrace("Running stats cleanup tasks... ");
474 // delete dailies older than 2 months (to be safe)
475 $deletebefore = stats_get_next_monthend(strtotime('-2 months',time()));
476 delete_records_select('stats_daily',"timeend < $deletebefore");
477 delete_records_select('stats_user_daily',"timeend < $deletebefore");
479 // delete weeklies older than 8 months (to be safe)
480 $deletebefore = stats_get_next_monthend(strtotime('-8 months',time()));
481 delete_records_select('stats_weekly',"timeend < $deletebefore");
482 delete_records_select('stats_user_weekly',"timeend < $deletebefore");
484 // don't delete monthlies
487 function stats_get_parameters($time,$report,$courseid,$mode) {
489 if ($time < 10) { // dailies
490 // number of days to go back = 7* time
491 $param->table
= 'daily';
492 $param->timeafter
= strtotime("-".($time*7)." days",stats_get_base_daily());
493 } elseif ($time < 20) { // weeklies
494 // number of weeks to go back = time - 10 * 4 (weeks) + base week
495 $param->table
= 'weekly';
496 $param->timeafter
= strtotime("-".(($time - 10)*4)." weeks",stats_get_base_weekly());
497 } else { // monthlies.
498 // number of months to go back = time - 20 * months + base month
499 $param->table
= 'monthly';
500 $param->timeafter
= strtotime("-".($time - 20)." months",stats_get_base_monthly());
505 // compatibility - if we're in postgres, cast to real for some reports.
507 if ($CFG->dbtype
== 'postgres7') {
512 case STATS_REPORT_LOGINS
:
513 $param->fields
= 'logins as line1,uniquelogins as line2';
514 $param->line1
= get_string('statslogins');
515 $param->line2
= get_string('statsuniquelogins');
517 case STATS_REPORT_READS
:
518 $param->fields
= 'studentreads as line1,teacherreads as line2';
519 $param->line1
= get_string('statsstudentreads');
520 $param->line2
= get_string('statsteacherreads');
522 case STATS_REPORT_WRITES
:
523 $param->fields
= 'studentwrites as line1,teacherwrites as line2';
524 $param->line1
= get_string('statsstudentwrites');
525 $param->line2
= get_string('statsteacherwrites');
527 case STATS_REPORT_ACTIVITY
:
528 $param->fields
= 'studentreads+studentwrites as line1, teacherreads+teacherwrites as line2';
529 $param->line1
= get_string('statsstudentactivity');
530 $param->line2
= get_string('statsteacheractivity');
532 case STATS_REPORT_STUDENTACTIVITY
:
533 $param->fields
= 'studentreads as line1,studentwrites as line2';
534 $param->line1
= get_string('statsstudentreads');
535 $param->line2
= get_string('statsstudentwrites');
537 case STATS_REPORT_TEACHERACTIVITY
:
538 $param->fields
= 'teacherreads as line1,teacherwrites as line2';
539 $param->line1
= get_string('statsteacherreads');
540 $param->line2
= get_string('statsteacherwrites');
542 case STATS_REPORT_USER_ACTIVITY
:
543 $param->fields
= 'statsreads as line1, statswrites as line2';
544 $param->line1
= get_string('statsuserreads');
545 $param->line2
= get_string('statsuserwrites');
546 $param->stattype
= 'activity';
548 case STATS_REPORT_USER_ALLACTIVITY
:
549 $param->fields
= 'statsreads+statswrites as line1';
550 $param->line1
= get_string('statsuseractivity');
551 $param->stattype
= 'activity';
553 case STATS_REPORT_USER_LOGINS
:
554 $param->fields
= 'statsreads as line1';
555 $param->line1
= get_string('statsuserlogins');
556 $param->stattype
= 'logins';
558 case STATS_REPORT_USER_VIEW
:
559 $param->fields
= 'statsreads as line1, statswrites as line2, statsreads+statswrites as line3';
560 $param->line1
= get_string('statsuserreads');
561 $param->line2
= get_string('statsuserwrites');
562 $param->line3
= get_string('statsuseractivity');
563 $param->stattype
= 'activity';
565 case STATS_REPORT_ACTIVE_COURSES
:
566 $param->fields
= 'sum(studentreads+studentwrites+teacherreads+teacherwrites) AS line1';
567 $param->orderby
= 'line1 DESC';
568 $param->line1
= get_string('activity');
569 $param->graphline
= 'line1';
571 case STATS_REPORT_ACTIVE_COURSES_WEIGHTED
:
572 $param->fields
= 'sum(studentreads+studentwrites+teacherreads+teacherwrites) AS line1,'
573 .'max(students+teachers) AS line2,'
574 .'sum(studentreads+studentwrites+teacherreads+teacherwrites)'.$real.'/max(students+teachers)'.$real.' AS line3';
575 $param->extras
= 'HAVING max(students+teachers) != 0';
576 if (!empty($CFG->statsuserthreshold
) && is_numeric($CFG->statsuserthreshold
)) {
577 $param->extras
.= ' AND max(students+teachers) > '.$CFG->statsuserthreshold
;
579 $param->orderby
= 'line3 DESC';
580 $param->line1
= get_string('activity');
581 $param->line2
= get_string('users');
582 $param->line3
= get_string('activityweighted');
583 $param->graphline
= 'line3';
585 case STATS_REPORT_PARTICIPATORY_COURSES
:
586 $param->fields
= 'max(students+teachers) as line1,max(activestudents+activeteachers) AS line2,'
587 .'max(activestudents+activeteachers)'.$real.'/max(students+teachers)'.$real.' AS line3';
588 $param->extras
= 'HAVING max(students+teachers) != 0';
589 if (!empty($CFG->statsuserthreshold
) && is_numeric($CFG->statsuserthreshold
)) {
590 $param->extras
.= ' AND max(students+teachers) > '.$CFG->statsuserthreshold
;
592 $param->orderby
= 'line3 DESC';
593 $param->line1
= get_string('users');
594 $param->line2
= get_string('activeusers');
595 $param->line3
= get_string('participationratio');
596 $param->graphline
= 'line3';
598 case STATS_REPORT_PARTICIPATORY_COURSES_RW
:
599 $param->fields
= 'sum(studentreads+teacherreads) as line1,sum(studentwrites+teacherwrites) AS line2,'
600 .'sum(studentwrites+teacherwrites)'.$real.'/sum(studentreads+teacherreads)'.$real.' AS line3';
601 $param->extras
= 'HAVING sum(studentreads+teacherreads) != 0';
602 $param->orderby
= 'line3 DESC';
603 $param->line1
= get_string('views');
604 $param->line2
= get_string('posts');
605 $param->line3
= get_string('participationratio');
606 $param->graphline
= 'line3';
610 if ($courseid == SITEID
&& $mode != STATS_MODE_RANKED
) { // just aggregate all courses.
611 $param->fields
= preg_replace('/([a-zA-Z0-9+_]*)\W+as\W+([a-zA-Z0-9_]*)/','sum($1) as $2',$param->fields
);
612 $param->extras
= ' GROUP BY timeend';
618 function stats_get_view_actions() {
619 return array('view','view all','history');
622 function stats_get_post_actions() {
623 return array('add','delete','edit','add mod','delete mod','edit section'.'enrol','loginas','new','unenrol','update','update mod');
626 function stats_get_action_sql_in($str) {
629 $mods = get_records('modules');
630 $function = 'stats_get_'.$str.'_actions';
631 $actions = $function();
632 foreach ($mods as $mod) {
633 require_once($CFG->dirroot
.'/mod/'.$mod->name
.'/lib.php');
634 $function = $mod->name
.'_get_'.$str.'_actions';
635 if (function_exists($function)) {
636 $actions = array_merge($actions,$function());
639 $actions = array_unique($actions);
640 if (empty($actions)) {
642 } else if (count($actions) == 1) {
643 return ' AND l.action = '.array_pop($actions).' ';
645 return ' AND l.action IN (\''.implode('\',\'',$actions).'\') ';
650 function stats_get_course_users($course,$timesql,&$students, &$teachers) {
653 $timesql = str_replace('timeend','l.time',$timesql);
655 $sql = 'SELECT DISTINCT(l.userid) as userid,1 as roleid FROM '.$CFG->prefix
.'log l JOIN '.$CFG->prefix
656 .'user_students us ON us.userid = l.userid WHERE l.course = '.$course->id
.' AND us.course = '.$course->id
.' AND '.$timesql;
657 if (!$students = get_records_sql($sql)) {
658 $students = array(); // avoid warnings;
661 $sql = str_replace('students','teachers',$sql);
662 $sql = str_replace(',1',',2',$sql);
664 if (!$teachers = get_records_sql($sql)) {
665 $teachers = array(); // avoid warnings
670 function stats_do_daily_user_cron($course,$user,$roleid,$timesql,$timeend,$mods) {
674 $stat = new StdClass
;
675 $stat->userid
= $user->userid
;
676 $stat->roleid
= $roleid;
677 $stat->courseid
= $course->id
;
678 $stat->stattype
= 'activity';
679 $stat->timeend
= $timeend;
681 $sql = 'SELECT COUNT(l.id) FROM '.$CFG->prefix
.'log l WHERE l.userid = '.$user->userid
682 .' AND l.course = '.$course->id
683 .' AND '.$timesql .' '.stats_get_action_sql_in('view');
685 $stat->statsreads
= count_records_sql($sql);
687 $sql = 'SELECT COUNT(l.id) FROM '.$CFG->prefix
.'log l WHERE l.userid = '.$user->userid
688 .' AND l.course = '.$course->id
689 .' AND '.$timesql.' '.stats_get_action_sql_in('post');
691 $stat->statswrites
= count_records_sql($sql);
693 insert_record('stats_user_daily',$stat,false);
695 // now ask the modules if they want anything.
696 foreach ($mods as $mod => $fname) {
697 mtrace(' doing daily statistics for '.$mod->name
);
698 $fname($course,$user,$timeend,$roleid);
702 function stats_do_aggregate_user_cron($course,$user,$roleid,$timesql,$timeend,$timestr,$mods) {
706 $stat = new StdClass
;
707 $stat->userid
= $user->userid
;
708 $stat->roleid
= $roleid;
709 $stat->courseid
= $course->id
;
710 $stat->stattype
= 'activity';
711 $stat->timeend
= $timeend;
713 $sql = 'SELECT sum(statsreads) as statsreads, sum(statswrites) as statswrites FROM '.$CFG->prefix
.'stats_user_daily WHERE courseid = '.$course->id
.' AND '.$timesql
714 ." AND roleid=".$roleid." AND userid = ".$stat->userid
." AND stattype='activity'"; // add on roleid in case they have teacher and student records.
716 $r = get_record_sql($sql);
717 $stat->statsreads
= (empty($r->statsreads
)) ?
0 : $r->statsreads
;
718 $stat->statswrites
= (empty($r->statswrites
)) ?
0 : $r->statswrites
;
720 insert_record('stats_user_'.$timestr,$stat,false);
722 // now ask the modules if they want anything.
723 foreach ($mods as $mod => $fname) {
724 mtrace(' doing '.$timestr.' statistics for '.$mod->name
);
725 $fname($course,$user,$timeend,$roleid);
729 function stats_do_aggregate_user_login_cron($timesql,$timeend,$timestr) {
732 $sql = 'SELECT userid,roleid,sum(statsreads) as statsreads, sum(statswrites) as writes FROM '.$CFG->prefix
.'stats_user_daily WHERE stattype = \'logins\' AND '.$timesql.' GROUP BY userid,roleid';
734 if ($users = get_records_sql($sql)) {
735 foreach ($users as $stat) {
736 $stat->courseid
= SITEID
;
737 $stat->timeend
= $timeend;
738 $stat->stattype
= 'logins';
740 insert_record('stats_user_'.$timestr,$stat,false);
746 function stats_get_time_options($now,$lastweekend,$lastmonthend,$earliestday,$earliestweek,$earliestmonth) {
748 $now = stats_get_base_daily(time());
749 // it's really important that it's TIMEEND in the table. ie, tuesday 00:00:00 is monday night.
750 // so we need to take a day off here (essentially add a day to $now
753 $timeoptions = array();
755 if ($now - (60*60*24*7) >= $earliestday) {
756 $timeoptions[STATS_TIME_LASTWEEK
] = get_string('numweeks','moodle',1);
758 if ($now - (60*60*24*14) >= $earliestday) {
759 $timeoptions[STATS_TIME_LAST2WEEKS
] = get_string('numweeks','moodle',2);
761 if ($now - (60*60*24*21) >= $earliestday) {
762 $timeoptions[STATS_TIME_LAST3WEEKS
] = get_string('numweeks','moodle',3);
764 if ($now - (60*60*24*28) >= $earliestday) {
765 $timeoptions[STATS_TIME_LAST4WEEKS
] = get_string('numweeks','moodle',4);// show dailies up to (including) here.
767 if ($lastweekend - (60*60*24*56) >= $earliestweek) {
768 $timeoptions[STATS_TIME_LAST2MONTHS
] = get_string('nummonths','moodle',2);
770 if ($lastweekend - (60*60*24*84) >= $earliestweek) {
771 $timeoptions[STATS_TIME_LAST3MONTHS
] = get_string('nummonths','moodle',3);
773 if ($lastweekend - (60*60*24*112) >= $earliestweek) {
774 $timeoptions[STATS_TIME_LAST4MONTHS
] = get_string('nummonths','moodle',4);
776 if ($lastweekend - (60*60*24*140) >= $earliestweek) {
777 $timeoptions[STATS_TIME_LAST5MONTHS
] = get_string('nummonths','moodle',5);
779 if ($lastweekend - (60*60*24*168) >= $earliestweek) {
780 $timeoptions[STATS_TIME_LAST6MONTHS
] = get_string('nummonths','moodle',6); // show weeklies up to (including) here
782 if (strtotime('-7 months',$lastmonthend) >= $earliestmonth) {
783 $timeoptions[STATS_TIME_LAST7MONTHS
] = get_string('nummonths','moodle',7);
785 if (strtotime('-8 months',$lastmonthend) >= $earliestmonth) {
786 $timeoptions[STATS_TIME_LAST8MONTHS
] = get_string('nummonths','moodle',8);
788 if (strtotime('-9 months',$lastmonthend) >= $earliestmonth) {
789 $timeoptions[STATS_TIME_LAST9MONTHS
] = get_string('nummonths','moodle',9);
791 if (strtotime('-10 months',$lastmonthend) >= $earliestmonth) {
792 $timeoptions[STATS_TIME_LAST10MONTHS
] = get_string('nummonths','moodle',10);
794 if (strtotime('-11 months',$lastmonthend) >= $earliestmonth) {
795 $timeoptions[STATS_TIME_LAST11MONTHS
] = get_string('nummonths','moodle',11);
797 if (strtotime('-1 year',$lastmonthend) >= $earliestmonth) {
798 $timeoptions[STATS_TIME_LASTYEAR
] = get_string('lastyear');
804 function stats_get_report_options($courseid,$mode) {
806 $reportoptions = array();
809 case STATS_MODE_GENERAL
:
810 $reportoptions[STATS_REPORT_ACTIVITY
] = get_string('statsreport'.STATS_REPORT_ACTIVITY
);
811 $reportoptions[STATS_REPORT_STUDENTACTIVITY
] = get_string('statsreport'.STATS_REPORT_STUDENTACTIVITY
);
812 $reportoptions[STATS_REPORT_TEACHERACTIVITY
] = get_string('statsreport'.STATS_REPORT_TEACHERACTIVITY
);
813 $reportoptions[STATS_REPORT_READS
] = get_string('statsreport'.STATS_REPORT_READS
);
814 $reportoptions[STATS_REPORT_WRITES
] = get_string('statsreport'.STATS_REPORT_WRITES
);
815 if ($courseid == SITEID
) {
816 $reportoptions[STATS_REPORT_LOGINS
] = get_string('statsreport'.STATS_REPORT_LOGINS
);
820 case STATS_MODE_DETAILED
:
821 $reportoptions[STATS_REPORT_USER_ACTIVITY
] = get_string('statsreport'.STATS_REPORT_USER_ACTIVITY
);
822 $reportoptions[STATS_REPORT_USER_ALLACTIVITY
] = get_string('statsreport'.STATS_REPORT_USER_ALLACTIVITY
);
825 $reportoptions[STATS_REPORT_USER_LOGINS
] = get_string('statsreport'.STATS_REPORT_USER_LOGINS
);
828 case STATS_MODE_RANKED
:
830 $reportoptions[STATS_REPORT_ACTIVE_COURSES
] = get_string('statsreport'.STATS_REPORT_ACTIVE_COURSES
);
831 $reportoptions[STATS_REPORT_ACTIVE_COURSES_WEIGHTED
] = get_string('statsreport'.STATS_REPORT_ACTIVE_COURSES_WEIGHTED
);
832 $reportoptions[STATS_REPORT_PARTICIPATORY_COURSES
] = get_string('statsreport'.STATS_REPORT_PARTICIPATORY_COURSES
);
833 $reportoptions[STATS_REPORT_PARTICIPATORY_COURSES_RW
] = get_string('statsreport'.STATS_REPORT_PARTICIPATORY_COURSES_RW
);
838 return $reportoptions;
841 function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) {
847 $timestr = str_replace('user_','',$timestr); // just in case.
848 $fun = 'stats_get_base_'.$timestr;
853 // add something to timeafter since it is our absolute base
854 $actualtimes = array_keys($stats);
855 $timeafter = array_pop($actualtimes);
857 while ($timeafter < $now) {
858 $times[] = $timeafter;
859 if ($timestr == 'daily') {
860 $timeafter = stats_get_next_dayend($timeafter);
861 } else if ($timestr == 'weekly') {
862 $timeafter = stats_get_next_weekend($timeafter);
863 } else if ($timestr == 'monthly') {
864 $timeafter = stats_get_next_monthend($timeafter);
866 return $stats; // this will put us in a never ending loop.
870 foreach ($times as $time) {
871 if (!array_key_exists($time,$stats)) {
872 $newobj = new StdClass
;
873 $newobj->timeend
= $time;
876 if (!empty($line2)) {
879 if (!empty($line3)) {
882 $stats[$time] = $newobj;
891 function stats_check_runtime() {
894 if (empty($CFG->statsmaxruntime
)) {
898 if ((time() - $CFG->statsrunning
) < $CFG->statsmaxruntime
) {
902 return false; // we've gone over!
906 function stats_check_uptodate($courseid=0) {
909 if (empty($courseid)) {
913 $latestday = stats_get_start_from('daily');
915 if ((time() - 60*60*24*2) < $latestday) { // we're ok
920 $a->daysdone
= get_field_sql("SELECT count(distinct(timeend)) from {$CFG->prefix}stats_daily");
922 // how many days between the last day and now?
923 $a->dayspending
= ceil((stats_get_base_daily() - $latestday)/(60*60*24));
925 if ($a->dayspending
== 0 && $a->daysdone
!= 0) {
926 return NULL; // we've only just started...
929 //return error as string
930 return get_string('statscatchupmode','error',$a);
934 // copied from usergetmidnight, but we ignore dst
935 function stats_getmidnight($date, $timezone=99) {
936 $timezone = get_user_timezone_offset($timezone);
937 $userdate = stats_getdate($date, $timezone);
938 return make_timestamp($userdate['year'], $userdate['mon'], $userdate['mday'], 0, 0, 0, $timezone,false ); // ignore dst for this.
941 function stats_getdate($time, $timezone=99) {
943 $timezone = get_user_timezone_offset($timezone);
945 if (abs($timezone) > 13) { // Server time
946 return getdate($time);
949 // There is no gmgetdate so we use gmdate instead
950 $time +
= intval((float)$timezone * HOURSECS
);
951 $datestring = strftime('%S_%M_%H_%d_%m_%Y_%w_%j_%A_%B', $time);
963 ) = explode('_', $datestring);