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 $file = $CFG->dirroot
.'/mod/'.$mod->name
.'/lib.php';
86 if (!is_readable($file)) {
90 $fname = $mod->name
.'_get_daily_stats';
91 if (function_exists($fname)) {
92 $daily_modules[$mod] = $fname;
97 $nextmidnight = stats_get_next_dayend($timestart);
99 if (!$courses = get_records('course','','','','id,1')) {
100 return STATS_RUN_ABORTED
;
104 mtrace("starting at $timestart");
105 while ($midnight > $nextmidnight && $timestart < $nextmidnight) {
107 $timesql = " (l.time > $timestart AND l.time < $nextmidnight) ";
109 foreach ($courses as $course) {
111 $stat->students
= count_records('user_students','course',$course->id
);
112 $stat->teachers
= count_records('user_teachers','course',$course->id
);
114 $sql = 'SELECT COUNT(DISTINCT(l.userid)) FROM '.$CFG->prefix
.'log l JOIN '.$CFG->prefix
115 .'user_students us ON us.userid = l.userid WHERE l.course = '.$course->id
.' AND us.course = '.$course->id
.' AND '.$timesql;
116 $stat->activestudents
= count_records_sql($sql);
118 $sql = str_replace('students','teachers',$sql);
119 $stat->activeteachers
= count_records_sql($sql);
121 $sql = 'SELECT COUNT(l.id) FROM '.$CFG->prefix
.'log l JOIN '.$CFG->prefix
122 .'user_students us ON us.userid = l.userid WHERE l.course = '.$course->id
.' AND us.course = '.$course->id
123 .' AND '.$timesql .' '.stats_get_action_sql_in('view');
124 $stat->studentreads
= count_records_sql($sql);
126 $sql = str_replace('students','teachers',$sql);
127 $stat->teacherreads
= count_records_sql($sql);
129 $sql = 'SELECT COUNT(l.id) FROM '.$CFG->prefix
.'log l JOIN '.$CFG->prefix
130 .'user_students us ON us.userid = l.userid WHERE l.course = '.$course->id
.' AND us.course = '.$course->id
131 .' AND '.$timesql.' '.stats_get_action_sql_in('post');
132 $stat->studentwrites
= count_records_sql($sql);
134 $sql = str_replace('students','teachers',$sql);
135 $stat->teacherwrites
= count_records_sql($sql);
138 $stat->uniquelogins
= 0;
139 if ($course->id
== SITEID
) {
140 $sql = 'SELECT count(l.id) FROM '.$CFG->prefix
.'log l WHERE l.action = \'login\' AND '.$timesql;
141 $stat->logins
= count_records_sql($sql);
142 $sql = 'SELECT COUNT(DISTINCT(l.userid)) FROM '.$CFG->prefix
.'log l WHERE l.action = \'login\' AND '.$timesql;
143 $stat->uniquelogins
= count_records_sql($sql);
146 $stat->courseid
= $course->id
;
147 $stat->timeend
= $nextmidnight;
148 insert_record('stats_daily',$stat,false); // don't worry about the return id, we don't need it.
154 if ($course->id
== SITEID
) {
155 $sql = 'SELECT l.userid,count(l.id) as count FROM '.$CFG->prefix
.'log l WHERE action = \'login\' AND '.$timesql.' GROUP BY userid';
157 if ($logins = get_records_sql($sql)) {
158 foreach ($logins as $l) {
159 $stat->statsreads
= $l->count
;
160 $stat->userid
= $l->userid
;
161 $stat->timeend
= $nextmidnight;
162 $stat->courseid
= SITEID
;
163 $stat->statswrites
= 0;
164 $stat->stattype
= 'logins';
166 insert_record('stats_user_daily',$stat,false);
172 stats_get_course_users($course,$timesql,$students,$teachers);
174 foreach ($students as $user) {
175 stats_do_daily_user_cron($course,$user,1,$timesql,$nextmidnight,$daily_modules);
177 foreach ($teachers as $user) {
178 stats_do_daily_user_cron($course,$user,2,$timesql,$nextmidnight,$daily_modules);
182 $timestart = $nextmidnight;
183 $nextmidnight = stats_get_next_dayend($nextmidnight);
186 if (!stats_check_runtime()) {
187 mtrace("Stopping early! reached maxruntime");
188 $return = STATS_RUN_ABORTED
;
192 mtrace("got up to ".$timestart);
193 mtrace("Completed $days days");
199 function stats_cron_weekly () {
203 if (empty($CFG->enablestats
)) {
207 if (!$timestart = stats_get_start_from('weekly')) {
208 return STATS_RUN_ABORTED
;
211 // check to make sure we're due to run, at least one week after last run
212 $sunday = stats_get_base_weekly();
214 if (isset($CFG->statslastweekly
) and ((time() - (7*24*60*60)) <= $CFG->statslastweekly
)) {
215 return STATS_RUN_ABORTED
;
218 mtrace("Running weekly statistics gathering...");
219 set_config('statslastweekly',time());
221 $return = STATS_RUN_COMPLETE
; // optimistic
223 static $weekly_modules;
225 if (empty($weekly_modules)) {
226 $weekly_modules = array();
227 $mods = get_records("modules");
228 foreach ($mods as $mod) {
229 $file = $CFG->dirroot
.'/mod/'.$mod->name
.'/lib.php';
230 if (!is_readable($file)) {
234 $fname = $mod->name
.'_get_weekly_stats';
235 if (function_exists($fname)) {
236 $weekly_modules[$mod] = $fname;
241 $nextsunday = stats_get_next_weekend($timestart);
243 if (!$courses = get_records('course','','','','id,1')) {
244 return STATS_RUN_ABORTED
;
248 mtrace("starting at $timestart");
249 while ($sunday > $nextsunday && $timestart < $nextsunday) {
251 $timesql = " (timeend > $timestart AND timeend < $nextsunday) ";
253 foreach ($courses as $course) {
255 $sql = 'SELECT ceil(avg(students)) as students, ceil(avg(teachers)) as teachers,
256 ceil(avg(activestudents)) as activestudents,ceil(avg(activeteachers)) as activeteachers,
257 sum(studentreads) as studentreads, sum(studentwrites) as studentwrites,
258 sum(teacherreads) as teacherreads, sum(teacherwrites) as teacherwrites,
259 sum(logins) as logins FROM '.$CFG->prefix
.'stats_daily WHERE courseid = '.$course->id
.' AND '.$timesql;
261 $stat = get_record_sql($sql);
263 $stat->uniquelogins
= 0;
264 if ($course->id
== SITEID
) {
265 $sql = 'SELECT COUNT(DISTINCT(l.userid)) FROM '.$CFG->prefix
.'log l WHERE l.action = \'login\' AND '
266 .str_replace('timeend','time',$timesql);
267 $stat->uniquelogins
= count_records_sql($sql);
270 $stat->courseid
= $course->id
;
271 $stat->timeend
= $nextsunday;
273 foreach (array_keys((array)$stat) as $key) {
274 if (!isset($stat->$key)) {
275 $stat->$key = 0; // we don't want nulls , so avoid them.
279 insert_record('stats_weekly',$stat,false); // don't worry about the return id, we don't need it.
284 stats_get_course_users($course,$timesql,$students,$teachers);
286 foreach ($students as $user) {
287 stats_do_aggregate_user_cron($course,$user,1,$timesql,$nextsunday,'weekly',$weekly_modules);
290 foreach ($teachers as $user) {
291 stats_do_aggregate_user_cron($course,$user,2,$timesql,$nextsunday,'weekly',$weekly_modules);
295 stats_do_aggregate_user_login_cron($timesql,$nextsunday,'weekly');
297 $timestart = $nextsunday;
298 $nextsunday = stats_get_next_weekend($nextsunday);
301 if (!stats_check_runtime()) {
302 mtrace("Stopping early! reached maxruntime");
303 $return = STATS_RUN_ABORTED
;
307 mtrace("got up to ".$timestart);
308 mtrace("Completed $weeks weeks");
313 function stats_cron_monthly () {
316 if (empty($CFG->enablestats
)) {
317 return STATS_RUN_ABORTED
;
320 if (!$timestart = stats_get_start_from('monthly')) {
321 return STATS_RUN_ABORTED
;
324 // check to make sure we're due to run, at least one month after last run
325 $monthend = stats_get_base_monthly();
327 if (isset($CFG->statslastmonthly
) and ((time() - (31*24*60*60)) <= $CFG->statslastmonthly
)) {
328 return STATS_RUN_ABORTED
;
331 mtrace("Running monthly statistics gathering...");
332 set_config('statslastmonthly',time());
334 $return = STATS_RUN_COMPLETE
; // optimistic
336 static $monthly_modules;
338 if (empty($monthly_modules)) {
339 $monthly_modules = array();
340 $mods = get_records("modules");
341 foreach ($mods as $mod) {
342 $file = $CFG->dirroot
.'/mod/'.$mod->name
.'/lib.php';
343 if (!is_readable($file)) {
347 $fname = $mod->name
.'_get_monthly_stats';
348 if (function_exists($fname)) {
349 $monthly_modules[$mod] = $fname;
354 $nextmonthend = stats_get_next_monthend($timestart);
356 if (!$courses = get_records('course','','','','id,1')) {
357 return STATS_RUN_ABORTED
;
361 mtrace("starting from $timestart");
362 while ($monthend > $nextmonthend && $timestart < $nextmonthend) {
364 $timesql = " (timeend > $timestart AND timeend < $nextmonthend) ";
366 foreach ($courses as $course) {
368 $sql = 'SELECT ceil(avg(students)) as students, ceil(avg(teachers)) as teachers, ceil(avg(activestudents)) as activestudents,ceil(avg(activeteachers)) as activeteachers,
369 sum(studentreads) as studentreads, sum(studentwrites) as studentwrites, sum(teacherreads) as teacherreads, sum(teacherwrites) as teacherwrites,
370 sum(logins) as logins FROM '.$CFG->prefix
.'stats_daily WHERE courseid = '.$course->id
.' AND '.$timesql;
372 $stat = get_record_sql($sql);
374 $stat->uniquelogins
= 0;
375 if ($course->id
== SITEID
) {
376 $sql = 'SELECT COUNT(DISTINCT(l.userid)) FROM '.$CFG->prefix
.'log l WHERE l.action = \'login\' AND '.str_replace('timeend','time',$timesql);
377 $stat->uniquelogins
= count_records_sql($sql);
380 $stat->courseid
= $course->id
;
381 $stat->timeend
= $nextmonthend;
383 foreach (array_keys((array)$stat) as $key) {
384 if (!isset($stat->$key)) {
385 $stat->$key = 0; // we don't want nulls , so avoid them.
389 insert_record('stats_monthly',$stat,false); // don't worry about the return id, we don't need it.
394 stats_get_course_users($course,$timesql,$students,$teachers);
396 foreach ($students as $user) {
397 stats_do_aggregate_user_cron($course,$user,1,$timesql,$nextmonthend,'monthly',$monthly_modules);
400 foreach ($teachers as $user) {
401 stats_do_aggregate_user_cron($course,$user,2,$timesql,$nextmonthend,'monthly',$monthly_modules);
404 stats_do_aggregate_user_login_cron($timesql,$nextmonthend,'monthly');
406 $timestart = $nextmonthend;
407 $nextmonthend = stats_get_next_monthend($timestart);
409 if (!stats_check_runtime()) {
410 mtrace("Stopping early! reached maxruntime");
412 $return = STATS_RUN_ABORTED
;
415 mtrace("got up to $timestart");
416 mtrace("Completed $months months");
420 function stats_get_start_from($str) {
423 // if it's not our first run, just return the most recent.
424 if ($timeend = get_field_sql('SELECT timeend FROM '.$CFG->prefix
.'stats_'.$str.' ORDER BY timeend DESC LIMIT 1')) {
428 // decide what to do based on our config setting (either all or none or a timestamp)
429 $function = 'stats_get_base_'.$str;
430 switch ($CFG->statsfirstrun
) {
432 return $function(get_field_sql('SELECT time FROM '.$CFG->prefix
.'log ORDER BY time LIMIT 1'));
435 return $function(strtotime('-1 day',time()));
438 if (is_numeric($CFG->statsfirstrun
)) {
439 return $function(time() - $CFG->statsfirstrun
);
446 function stats_get_base_daily($time=0) {
450 return stats_getmidnight($time);
453 function stats_get_base_weekly($time=0) {
457 // if we're currently a monday, last monday will take us back a week
458 $str = 'last monday';
459 if (date('D',$time) == 'Mon')
462 return stats_getmidnight(strtotime($str,$time));
465 function stats_get_base_monthly($time=0) {
469 return stats_getmidnight(strtotime(date('1-M-Y',$time)));
472 function stats_get_next_monthend($lastmonth) {
473 return stats_getmidnight(strtotime(date('1-M-Y',$lastmonth).' +1 month'));
476 function stats_get_next_weekend($lastweek) {
477 return stats_getmidnight(strtotime('+1 week',$lastweek));
480 function stats_get_next_dayend($lastday) {
481 return stats_getmidnight(strtotime('+1 day',$lastday));
484 function stats_clean_old() {
485 mtrace("Running stats cleanup tasks... ");
486 // delete dailies older than 2 months (to be safe)
487 $deletebefore = stats_get_next_monthend(strtotime('-2 months',time()));
488 delete_records_select('stats_daily',"timeend < $deletebefore");
489 delete_records_select('stats_user_daily',"timeend < $deletebefore");
491 // delete weeklies older than 8 months (to be safe)
492 $deletebefore = stats_get_next_monthend(strtotime('-8 months',time()));
493 delete_records_select('stats_weekly',"timeend < $deletebefore");
494 delete_records_select('stats_user_weekly',"timeend < $deletebefore");
496 // don't delete monthlies
499 function stats_get_parameters($time,$report,$courseid,$mode) {
501 if ($time < 10) { // dailies
502 // number of days to go back = 7* time
503 $param->table
= 'daily';
504 $param->timeafter
= strtotime("-".($time*7)." days",stats_get_base_daily());
505 } elseif ($time < 20) { // weeklies
506 // number of weeks to go back = time - 10 * 4 (weeks) + base week
507 $param->table
= 'weekly';
508 $param->timeafter
= strtotime("-".(($time - 10)*4)." weeks",stats_get_base_weekly());
509 } else { // monthlies.
510 // number of months to go back = time - 20 * months + base month
511 $param->table
= 'monthly';
512 $param->timeafter
= strtotime("-".($time - 20)." months",stats_get_base_monthly());
517 // compatibility - if we're in postgres, cast to real for some reports.
519 if ($CFG->dbtype
== 'postgres7') {
524 case STATS_REPORT_LOGINS
:
525 $param->fields
= 'logins as line1,uniquelogins as line2';
526 $param->line1
= get_string('statslogins');
527 $param->line2
= get_string('statsuniquelogins');
529 case STATS_REPORT_READS
:
530 $param->fields
= 'studentreads as line1,teacherreads as line2';
531 $param->line1
= get_string('statsstudentreads');
532 $param->line2
= get_string('statsteacherreads');
534 case STATS_REPORT_WRITES
:
535 $param->fields
= 'studentwrites as line1,teacherwrites as line2';
536 $param->line1
= get_string('statsstudentwrites');
537 $param->line2
= get_string('statsteacherwrites');
539 case STATS_REPORT_ACTIVITY
:
540 $param->fields
= 'studentreads+studentwrites as line1, teacherreads+teacherwrites as line2';
541 $param->line1
= get_string('statsstudentactivity');
542 $param->line2
= get_string('statsteacheractivity');
544 case STATS_REPORT_STUDENTACTIVITY
:
545 $param->fields
= 'studentreads as line1,studentwrites as line2';
546 $param->line1
= get_string('statsstudentreads');
547 $param->line2
= get_string('statsstudentwrites');
549 case STATS_REPORT_TEACHERACTIVITY
:
550 $param->fields
= 'teacherreads as line1,teacherwrites as line2';
551 $param->line1
= get_string('statsteacherreads');
552 $param->line2
= get_string('statsteacherwrites');
554 case STATS_REPORT_USER_ACTIVITY
:
555 $param->fields
= 'statsreads as line1, statswrites as line2';
556 $param->line1
= get_string('statsuserreads');
557 $param->line2
= get_string('statsuserwrites');
558 $param->stattype
= 'activity';
560 case STATS_REPORT_USER_ALLACTIVITY
:
561 $param->fields
= 'statsreads+statswrites as line1';
562 $param->line1
= get_string('statsuseractivity');
563 $param->stattype
= 'activity';
565 case STATS_REPORT_USER_LOGINS
:
566 $param->fields
= 'statsreads as line1';
567 $param->line1
= get_string('statsuserlogins');
568 $param->stattype
= 'logins';
570 case STATS_REPORT_USER_VIEW
:
571 $param->fields
= 'statsreads as line1, statswrites as line2, statsreads+statswrites as line3';
572 $param->line1
= get_string('statsuserreads');
573 $param->line2
= get_string('statsuserwrites');
574 $param->line3
= get_string('statsuseractivity');
575 $param->stattype
= 'activity';
577 case STATS_REPORT_ACTIVE_COURSES
:
578 $param->fields
= 'sum(studentreads+studentwrites+teacherreads+teacherwrites) AS line1';
579 $param->orderby
= 'line1 DESC';
580 $param->line1
= get_string('activity');
581 $param->graphline
= 'line1';
583 case STATS_REPORT_ACTIVE_COURSES_WEIGHTED
:
584 $param->fields
= 'sum(studentreads+studentwrites+teacherreads+teacherwrites) AS line1,'
585 .'max(students+teachers) AS line2,'
586 .'sum(studentreads+studentwrites+teacherreads+teacherwrites)'.$real.'/max(students+teachers)'.$real.' AS line3';
587 $param->extras
= 'HAVING max(students+teachers) != 0';
588 if (!empty($CFG->statsuserthreshold
) && is_numeric($CFG->statsuserthreshold
)) {
589 $param->extras
.= ' AND max(students+teachers) > '.$CFG->statsuserthreshold
;
591 $param->orderby
= 'line3 DESC';
592 $param->line1
= get_string('activity');
593 $param->line2
= get_string('users');
594 $param->line3
= get_string('activityweighted');
595 $param->graphline
= 'line3';
597 case STATS_REPORT_PARTICIPATORY_COURSES
:
598 $param->fields
= 'max(students+teachers) as line1,max(activestudents+activeteachers) AS line2,'
599 .'max(activestudents+activeteachers)'.$real.'/max(students+teachers)'.$real.' AS line3';
600 $param->extras
= 'HAVING max(students+teachers) != 0';
601 if (!empty($CFG->statsuserthreshold
) && is_numeric($CFG->statsuserthreshold
)) {
602 $param->extras
.= ' AND max(students+teachers) > '.$CFG->statsuserthreshold
;
604 $param->orderby
= 'line3 DESC';
605 $param->line1
= get_string('users');
606 $param->line2
= get_string('activeusers');
607 $param->line3
= get_string('participationratio');
608 $param->graphline
= 'line3';
610 case STATS_REPORT_PARTICIPATORY_COURSES_RW
:
611 $param->fields
= 'sum(studentreads+teacherreads) as line1,sum(studentwrites+teacherwrites) AS line2,'
612 .'sum(studentwrites+teacherwrites)'.$real.'/sum(studentreads+teacherreads)'.$real.' AS line3';
613 $param->extras
= 'HAVING sum(studentreads+teacherreads) != 0';
614 $param->orderby
= 'line3 DESC';
615 $param->line1
= get_string('views');
616 $param->line2
= get_string('posts');
617 $param->line3
= get_string('participationratio');
618 $param->graphline
= 'line3';
622 if ($courseid == SITEID
&& $mode != STATS_MODE_RANKED
) { // just aggregate all courses.
623 $param->fields
= preg_replace('/([a-zA-Z0-9+_]*)\W+as\W+([a-zA-Z0-9_]*)/','sum($1) as $2',$param->fields
);
624 $param->extras
= ' GROUP BY timeend';
630 function stats_get_view_actions() {
631 return array('view','view all','history');
634 function stats_get_post_actions() {
635 return array('add','delete','edit','add mod','delete mod','edit section'.'enrol','loginas','new','unenrol','update','update mod');
638 function stats_get_action_sql_in($str) {
641 $mods = get_records('modules');
642 $function = 'stats_get_'.$str.'_actions';
643 $actions = $function();
644 foreach ($mods as $mod) {
645 $file = $CFG->dirroot
.'/mod/'.$mod->name
.'/lib.php';
646 if (!is_readable($file)) {
650 $function = $mod->name
.'_get_'.$str.'_actions';
651 if (function_exists($function)) {
652 $actions = array_merge($actions,$function());
655 $actions = array_unique($actions);
656 if (empty($actions)) {
658 } else if (count($actions) == 1) {
659 return ' AND l.action = '.array_pop($actions).' ';
661 return ' AND l.action IN (\''.implode('\',\'',$actions).'\') ';
666 function stats_get_course_users($course,$timesql,&$students, &$teachers) {
669 $timesql = str_replace('timeend','l.time',$timesql);
671 $sql = 'SELECT DISTINCT(l.userid) as userid,1 as roleid FROM '.$CFG->prefix
.'log l JOIN '.$CFG->prefix
672 .'user_students us ON us.userid = l.userid WHERE l.course = '.$course->id
.' AND us.course = '.$course->id
.' AND '.$timesql;
673 if (!$students = get_records_sql($sql)) {
674 $students = array(); // avoid warnings;
677 $sql = str_replace('students','teachers',$sql);
678 $sql = str_replace(',1',',2',$sql);
680 if (!$teachers = get_records_sql($sql)) {
681 $teachers = array(); // avoid warnings
686 function stats_do_daily_user_cron($course,$user,$roleid,$timesql,$timeend,$mods) {
690 $stat = new StdClass
;
691 $stat->userid
= $user->userid
;
692 $stat->roleid
= $roleid;
693 $stat->courseid
= $course->id
;
694 $stat->stattype
= 'activity';
695 $stat->timeend
= $timeend;
697 $sql = 'SELECT COUNT(l.id) FROM '.$CFG->prefix
.'log l WHERE l.userid = '.$user->userid
698 .' AND l.course = '.$course->id
699 .' AND '.$timesql .' '.stats_get_action_sql_in('view');
701 $stat->statsreads
= count_records_sql($sql);
703 $sql = 'SELECT COUNT(l.id) FROM '.$CFG->prefix
.'log l WHERE l.userid = '.$user->userid
704 .' AND l.course = '.$course->id
705 .' AND '.$timesql.' '.stats_get_action_sql_in('post');
707 $stat->statswrites
= count_records_sql($sql);
709 insert_record('stats_user_daily',$stat,false);
711 // now ask the modules if they want anything.
712 foreach ($mods as $mod => $fname) {
713 mtrace(' doing daily statistics for '.$mod->name
);
714 $fname($course,$user,$timeend,$roleid);
718 function stats_do_aggregate_user_cron($course,$user,$roleid,$timesql,$timeend,$timestr,$mods) {
722 $stat = new StdClass
;
723 $stat->userid
= $user->userid
;
724 $stat->roleid
= $roleid;
725 $stat->courseid
= $course->id
;
726 $stat->stattype
= 'activity';
727 $stat->timeend
= $timeend;
729 $sql = 'SELECT sum(statsreads) as statsreads, sum(statswrites) as statswrites FROM '.$CFG->prefix
.'stats_user_daily WHERE courseid = '.$course->id
.' AND '.$timesql
730 ." AND roleid=".$roleid." AND userid = ".$stat->userid
." AND stattype='activity'"; // add on roleid in case they have teacher and student records.
732 $r = get_record_sql($sql);
733 $stat->statsreads
= (empty($r->statsreads
)) ?
0 : $r->statsreads
;
734 $stat->statswrites
= (empty($r->statswrites
)) ?
0 : $r->statswrites
;
736 insert_record('stats_user_'.$timestr,$stat,false);
738 // now ask the modules if they want anything.
739 foreach ($mods as $mod => $fname) {
740 mtrace(' doing '.$timestr.' statistics for '.$mod->name
);
741 $fname($course,$user,$timeend,$roleid);
745 function stats_do_aggregate_user_login_cron($timesql,$timeend,$timestr) {
748 $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';
750 if ($users = get_records_sql($sql)) {
751 foreach ($users as $stat) {
752 $stat->courseid
= SITEID
;
753 $stat->timeend
= $timeend;
754 $stat->stattype
= 'logins';
756 insert_record('stats_user_'.$timestr,$stat,false);
762 function stats_get_time_options($now,$lastweekend,$lastmonthend,$earliestday,$earliestweek,$earliestmonth) {
764 $now = stats_get_base_daily(time());
765 // it's really important that it's TIMEEND in the table. ie, tuesday 00:00:00 is monday night.
766 // so we need to take a day off here (essentially add a day to $now
769 $timeoptions = array();
771 if ($now - (60*60*24*7) >= $earliestday) {
772 $timeoptions[STATS_TIME_LASTWEEK
] = get_string('numweeks','moodle',1);
774 if ($now - (60*60*24*14) >= $earliestday) {
775 $timeoptions[STATS_TIME_LAST2WEEKS
] = get_string('numweeks','moodle',2);
777 if ($now - (60*60*24*21) >= $earliestday) {
778 $timeoptions[STATS_TIME_LAST3WEEKS
] = get_string('numweeks','moodle',3);
780 if ($now - (60*60*24*28) >= $earliestday) {
781 $timeoptions[STATS_TIME_LAST4WEEKS
] = get_string('numweeks','moodle',4);// show dailies up to (including) here.
783 if ($lastweekend - (60*60*24*56) >= $earliestweek) {
784 $timeoptions[STATS_TIME_LAST2MONTHS
] = get_string('nummonths','moodle',2);
786 if ($lastweekend - (60*60*24*84) >= $earliestweek) {
787 $timeoptions[STATS_TIME_LAST3MONTHS
] = get_string('nummonths','moodle',3);
789 if ($lastweekend - (60*60*24*112) >= $earliestweek) {
790 $timeoptions[STATS_TIME_LAST4MONTHS
] = get_string('nummonths','moodle',4);
792 if ($lastweekend - (60*60*24*140) >= $earliestweek) {
793 $timeoptions[STATS_TIME_LAST5MONTHS
] = get_string('nummonths','moodle',5);
795 if ($lastweekend - (60*60*24*168) >= $earliestweek) {
796 $timeoptions[STATS_TIME_LAST6MONTHS
] = get_string('nummonths','moodle',6); // show weeklies up to (including) here
798 if (strtotime('-7 months',$lastmonthend) >= $earliestmonth) {
799 $timeoptions[STATS_TIME_LAST7MONTHS
] = get_string('nummonths','moodle',7);
801 if (strtotime('-8 months',$lastmonthend) >= $earliestmonth) {
802 $timeoptions[STATS_TIME_LAST8MONTHS
] = get_string('nummonths','moodle',8);
804 if (strtotime('-9 months',$lastmonthend) >= $earliestmonth) {
805 $timeoptions[STATS_TIME_LAST9MONTHS
] = get_string('nummonths','moodle',9);
807 if (strtotime('-10 months',$lastmonthend) >= $earliestmonth) {
808 $timeoptions[STATS_TIME_LAST10MONTHS
] = get_string('nummonths','moodle',10);
810 if (strtotime('-11 months',$lastmonthend) >= $earliestmonth) {
811 $timeoptions[STATS_TIME_LAST11MONTHS
] = get_string('nummonths','moodle',11);
813 if (strtotime('-1 year',$lastmonthend) >= $earliestmonth) {
814 $timeoptions[STATS_TIME_LASTYEAR
] = get_string('lastyear');
820 function stats_get_report_options($courseid,$mode) {
822 $reportoptions = array();
825 case STATS_MODE_GENERAL
:
826 $reportoptions[STATS_REPORT_ACTIVITY
] = get_string('statsreport'.STATS_REPORT_ACTIVITY
);
827 $reportoptions[STATS_REPORT_STUDENTACTIVITY
] = get_string('statsreport'.STATS_REPORT_STUDENTACTIVITY
);
828 $reportoptions[STATS_REPORT_TEACHERACTIVITY
] = get_string('statsreport'.STATS_REPORT_TEACHERACTIVITY
);
829 $reportoptions[STATS_REPORT_READS
] = get_string('statsreport'.STATS_REPORT_READS
);
830 $reportoptions[STATS_REPORT_WRITES
] = get_string('statsreport'.STATS_REPORT_WRITES
);
831 if ($courseid == SITEID
) {
832 $reportoptions[STATS_REPORT_LOGINS
] = get_string('statsreport'.STATS_REPORT_LOGINS
);
836 case STATS_MODE_DETAILED
:
837 $reportoptions[STATS_REPORT_USER_ACTIVITY
] = get_string('statsreport'.STATS_REPORT_USER_ACTIVITY
);
838 $reportoptions[STATS_REPORT_USER_ALLACTIVITY
] = get_string('statsreport'.STATS_REPORT_USER_ALLACTIVITY
);
841 $reportoptions[STATS_REPORT_USER_LOGINS
] = get_string('statsreport'.STATS_REPORT_USER_LOGINS
);
844 case STATS_MODE_RANKED
:
846 $reportoptions[STATS_REPORT_ACTIVE_COURSES
] = get_string('statsreport'.STATS_REPORT_ACTIVE_COURSES
);
847 $reportoptions[STATS_REPORT_ACTIVE_COURSES_WEIGHTED
] = get_string('statsreport'.STATS_REPORT_ACTIVE_COURSES_WEIGHTED
);
848 $reportoptions[STATS_REPORT_PARTICIPATORY_COURSES
] = get_string('statsreport'.STATS_REPORT_PARTICIPATORY_COURSES
);
849 $reportoptions[STATS_REPORT_PARTICIPATORY_COURSES_RW
] = get_string('statsreport'.STATS_REPORT_PARTICIPATORY_COURSES_RW
);
854 return $reportoptions;
857 function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) {
863 $timestr = str_replace('user_','',$timestr); // just in case.
864 $fun = 'stats_get_base_'.$timestr;
869 // add something to timeafter since it is our absolute base
870 $actualtimes = array_keys($stats);
871 $timeafter = array_pop($actualtimes);
873 while ($timeafter < $now) {
874 $times[] = $timeafter;
875 if ($timestr == 'daily') {
876 $timeafter = stats_get_next_dayend($timeafter);
877 } else if ($timestr == 'weekly') {
878 $timeafter = stats_get_next_weekend($timeafter);
879 } else if ($timestr == 'monthly') {
880 $timeafter = stats_get_next_monthend($timeafter);
882 return $stats; // this will put us in a never ending loop.
886 foreach ($times as $time) {
887 if (!array_key_exists($time,$stats)) {
888 $newobj = new StdClass
;
889 $newobj->timeend
= $time;
892 if (!empty($line2)) {
895 if (!empty($line3)) {
898 $stats[$time] = $newobj;
907 function stats_check_runtime() {
910 if (empty($CFG->statsmaxruntime
)) {
914 if ((time() - $CFG->statsrunning
) < $CFG->statsmaxruntime
) {
918 return false; // we've gone over!
922 function stats_check_uptodate($courseid=0) {
925 if (empty($courseid)) {
929 $latestday = stats_get_start_from('daily');
931 if ((time() - 60*60*24*2) < $latestday) { // we're ok
936 $a->daysdone
= get_field_sql("SELECT count(distinct(timeend)) from {$CFG->prefix}stats_daily");
938 // how many days between the last day and now?
939 $a->dayspending
= ceil((stats_get_base_daily() - $latestday)/(60*60*24));
941 if ($a->dayspending
== 0 && $a->daysdone
!= 0) {
942 return NULL; // we've only just started...
945 //return error as string
946 return get_string('statscatchupmode','error',$a);
950 // copied from usergetmidnight, but we ignore dst
951 function stats_getmidnight($date, $timezone=99) {
952 $timezone = get_user_timezone_offset($timezone);
953 $userdate = stats_getdate($date, $timezone);
954 return make_timestamp($userdate['year'], $userdate['mon'], $userdate['mday'], 0, 0, 0, $timezone,false ); // ignore dst for this.
957 function stats_getdate($time, $timezone=99) {
959 $timezone = get_user_timezone_offset($timezone);
961 if (abs($timezone) > 13) { // Server time
962 return getdate($time);
965 // There is no gmgetdate so we use gmdate instead
966 $time +
= intval((float)$timezone * HOURSECS
);
967 $datestring = strftime('%S_%M_%H_%d_%m_%Y_%w_%j_%A_%B', $time);
979 ) = explode('_', $datestring);