Automatic installer.php lang files by installer_builder (20070202)
[moodle.git] / lib / statslib.php
blob9e91de38a6d0772969f26d68eab8c8ed1fca72a7
1 <?php
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 () {
56 global $CFG;
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;
99 $days = 0;
100 mtrace("starting at $timestart");
101 while ($midnight > $nextmidnight && $timestart < $nextmidnight) {
103 $timesql = " (l.time > $timestart AND l.time < $nextmidnight) ";
104 begin_sql();
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);
133 $stat->logins = 0;
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.
146 $students = array();
147 $teachers = array();
149 // now do logins.
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';
161 $stat->roleid = 1;
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);
177 commit_sql();
178 $timestart = $nextmidnight;
179 $nextmidnight = stats_get_next_dayend($nextmidnight);
180 $days++;
182 if (!stats_check_runtime()) {
183 mtrace("Stopping early! reached maxruntime");
184 $return = STATS_RUN_ABORTED;
185 break;
188 mtrace("got up to ".$timestart);
189 mtrace("Completed $days days");
190 return $return;
195 function stats_cron_weekly () {
197 global $CFG;
199 if (empty($CFG->enablestats)) {
200 STATS_RUN_ABORTED;
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;
239 $weeks = 0;
240 mtrace("starting at $timestart");
241 while ($sunday > $nextsunday && $timestart < $nextsunday) {
243 $timesql = " (timeend > $timestart AND timeend < $nextsunday) ";
244 begin_sql();
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.
273 $students = array();
274 $teachers = array();
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');
288 commit_sql();
289 $timestart = $nextsunday;
290 $nextsunday = stats_get_next_weekend($nextsunday);
291 $weeks++;
293 if (!stats_check_runtime()) {
294 mtrace("Stopping early! reached maxruntime");
295 $return = STATS_RUN_ABORTED;
296 break;
299 mtrace("got up to ".$timestart);
300 mtrace("Completed $weeks weeks");
301 return $return;
305 function stats_cron_monthly () {
306 global $CFG;
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;
348 $months = 0;
349 mtrace("starting from $timestart");
350 while ($monthend > $nextmonthend && $timestart < $nextmonthend) {
352 $timesql = " (timeend > $timestart AND timeend < $nextmonthend) ";
353 begin_sql();
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.
379 $students = array();
380 $teachers = array();
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');
393 commit_sql();
394 $timestart = $nextmonthend;
395 $nextmonthend = stats_get_next_monthend($timestart);
396 $months++;
397 if (!stats_check_runtime()) {
398 mtrace("Stopping early! reached maxruntime");
399 break;
400 $return = STATS_RUN_ABORTED;
403 mtrace("got up to $timestart");
404 mtrace("Completed $months months");
405 return $return;
408 function stats_get_start_from($str) {
409 global $CFG;
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')) {
413 return $timeend;
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) {
419 case 'all':
420 return $function(get_field_sql('SELECT time FROM '.$CFG->prefix.'log ORDER BY time LIMIT 1'));
421 break;
422 case 'none':
423 return $function(strtotime('-1 day',time()));
424 break;
425 default:
426 if (is_numeric($CFG->statsfirstrun)) {
427 return $function(time() - $CFG->statsfirstrun);
429 return false;
430 break;
434 function stats_get_base_daily($time=0) {
435 if (empty($time)) {
436 $time = time();
438 return stats_getmidnight($time);
441 function stats_get_base_weekly($time=0) {
442 if (empty($time)) {
443 $time = time();
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')
448 $str = 'now';
450 return stats_getmidnight(strtotime($str,$time));
453 function stats_get_base_monthly($time=0) {
454 if (empty($time)) {
455 $time = time();
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) {
488 global $CFG;
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());
503 $param->extras = '';
505 // compatibility - if we're in postgres, cast to real for some reports.
506 $real = '';
507 if ($CFG->dbtype == 'postgres7') {
508 $real = '::real';
511 switch ($report) {
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');
516 break;
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');
521 break;
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');
526 break;
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');
531 break;
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');
536 break;
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');
541 break;
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';
547 break;
548 case STATS_REPORT_USER_ALLACTIVITY:
549 $param->fields = 'statsreads+statswrites as line1';
550 $param->line1 = get_string('statsuseractivity');
551 $param->stattype = 'activity';
552 break;
553 case STATS_REPORT_USER_LOGINS:
554 $param->fields = 'statsreads as line1';
555 $param->line1 = get_string('statsuserlogins');
556 $param->stattype = 'logins';
557 break;
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';
564 break;
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';
570 break;
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';
584 break;
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';
597 break;
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';
607 break;
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';
615 return $param;
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) {
627 global $CFG;
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)) {
641 return ' ';
642 } else if (count($actions) == 1) {
643 return ' AND l.action = '.array_pop($actions).' ';
644 } else {
645 return ' AND l.action IN (\''.implode('\',\'',$actions).'\') ';
650 function stats_get_course_users($course,$timesql,&$students, &$teachers) {
651 global $CFG;
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) {
672 global $CFG;
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) {
704 global $CFG;
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) {
730 global $CFG;
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
751 $now += 60*60*24;
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');
801 return $timeoptions;
804 function stats_get_report_options($courseid,$mode) {
806 $reportoptions = array();
808 switch ($mode) {
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);
819 break;
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);
823 if (isadmin()) {
824 $site = get_site();
825 $reportoptions[STATS_REPORT_USER_LOGINS] = get_string('statsreport'.STATS_REPORT_USER_LOGINS);
827 break;
828 case STATS_MODE_RANKED:
829 if (isadmin()) {
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);
835 break;
838 return $reportoptions;
841 function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) {
843 if (empty($stats)) {
844 return;
847 $timestr = str_replace('user_','',$timestr); // just in case.
848 $fun = 'stats_get_base_'.$timestr;
850 $now = $fun();
852 $times = array();
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);
865 } else {
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;
874 $newobj->id = 0;
875 $newobj->line1 = 0;
876 if (!empty($line2)) {
877 $newobj->line2 = 0;
879 if (!empty($line3)) {
880 $newobj->line3 = 0;
882 $stats[$time] = $newobj;
886 krsort($stats);
887 return $stats;
891 function stats_check_runtime() {
892 global $CFG;
894 if (empty($CFG->statsmaxruntime)) {
895 return true;
898 if ((time() - $CFG->statsrunning) < $CFG->statsmaxruntime) {
899 return true;
902 return false; // we've gone over!
906 function stats_check_uptodate($courseid=0) {
907 global $CFG;
909 if (empty($courseid)) {
910 $courseid = SITEID;
913 $latestday = stats_get_start_from('daily');
915 if ((time() - 60*60*24*2) < $latestday) { // we're ok
916 return NULL;
919 $a = new object();
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);
952 list(
953 $getdate['seconds'],
954 $getdate['minutes'],
955 $getdate['hours'],
956 $getdate['mday'],
957 $getdate['mon'],
958 $getdate['year'],
959 $getdate['wday'],
960 $getdate['yday'],
961 $getdate['weekday'],
962 $getdate['month']
963 ) = explode('_', $datestring);
965 return $getdate;