diff --git a/index.php b/index.php index 1b32c414a36..81d3e782954 100644 --- a/index.php +++ b/index.php @@ -64,6 +64,8 @@ if ($CFG->forcelogin) { require_login(); + } else { + user_accesstime_log(); } if ($CFG->rolesactive) { // if already using roles system diff --git a/lib/datalib.php b/lib/datalib.php index 287dd63716d..184b0b0e6be 100644 --- a/lib/datalib.php +++ b/lib/datalib.php @@ -10,6 +10,9 @@ * @package moodlecore */ + /// Some constants + define('LASTACCESS_UPDATE_SECS', 60); /// Number of seconds to wait before + /// updating lastaccess information in DB. /** * Escape all dangerous characters in a data record @@ -1938,52 +1941,100 @@ function add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user debugging('Error: Could not insert a new entry to the Moodle log', DEBUG_ALL); } -/// Store lastaccess times for the current user, do not use in cron and other commandline scripts -/// only update the lastaccess/timeaccess fields only once every 60s - if (!empty($USER->id) && ($userid == $USER->id) && !defined('FULLME')) { - /// Only update user and user_lastaccess every 60s, check that in PHP - if ($timenow - $USER->lastaccess > 60) { +} - if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++;}; - /// Update user record - $res = $db->Execute('UPDATE '. $CFG->prefix .'user - SET lastip=\''. $REMOTE_ADDR .'\', lastaccess=\''. $timenow .'\' - WHERE id = '. $userid); - if (!$res) { - debugging('Error: Could not update global user lastaccess information'); // Don't throw an error - } - /// Remove this record from record cache since it will change - if (!empty($CFG->rcache)) { - rcache_unset('user', $userid); - } - /// Update $USER->lastaccess for next checks - $USER->lastaccess = $timenow; +/** + * Store user last access times - called when use enters a course or site + * + * Note: we use ADOdb code directly in this function to save some CPU + * cycles here and there. They are simple operations not needing any + * of the postprocessing performed by dmllib.php + * + * @param int $courseid, empty means site + * @return void + */ +function user_accesstime_log($courseid=0) { - if ($courseid != SITEID && !empty($courseid)) { - if (record_exists('user_lastaccess', 'userid', $userid, 'courseid', $courseid)) { - if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++;}; - $res = $db->Execute("UPDATE {$CFG->prefix}user_lastaccess - SET timeaccess=$timenow - WHERE userid = $userid - AND courseid = $courseid"); - if (!$res) { - debugging('Error: Could not update course user lastacess information'); // Don't throw an error - } - } else { - if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++;}; - $res = $db->Execute("INSERT INTO {$CFG->prefix}user_lastaccess - ( userid, courseid, timeaccess) - VALUES ($userid, $courseid, $timenow)"); - if (!$res) { - debugging('Error: Could not insert course user lastaccess information'); // Don't throw an error - } + global $USER, $CFG, $PERF, $db; + + if (!isloggedin() or !empty($USER->realuser)) { + // no access tracking + return; + } + + if (empty($courseid)) { + $courseid = SITEID; + } + + $timenow = time(); + +/// Store site lastaccess time for the current user + if ($timenow - $USER->lastaccess > LASTACCESS_UPDATE_SECS) { + /// Update $USER->lastaccess for next checks + $USER->lastaccess = $timenow; + if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++;}; + + $remoteaddr = getremoteaddr(); + if ($db->Execute("UPDATE {$CFG->prefix}user + SET lastip = '$remoteaddr', lastaccess = $timenow + WHERE id = $USER->id")) { + } else { + debugging('Error: Could not update global user lastaccess information'); // Don't throw an error + } + /// Remove this record from record cache since it will change + if (!empty($CFG->rcache)) { + rcache_unset('user', $USER->id); + } + } + + if ($courseid == SITEID) { + /// no user_lastaccess for frontpage + return; + } + +/// Store course lastaccess times for the current user + if (empty($USER->currentcourseaccess[$courseid]) or ($timenow - $USER->currentcourseaccess[$courseid] > LASTACCESS_UPDATE_SECS)) { + if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; }; + + $exists = false; // To detect if the user_lastaccess record exists or no + if ($rs = $db->Execute("SELECT timeaccess + FROM {$CFG->prefix}user_lastaccess + WHERE userid = $USER->id AND courseid = $courseid")) { + if (!$rs->EOF) { + $exists = true; + $lastaccess = reset($rs->fields); + if ($timenow - $lastaccess < LASTACCESS_UPDATE_SECS) { + /// no need to update now, it was updated recently in concurrent login ;-) + $rs->Close(); + return; } } + $rs->Close(); + } + + /// Update course lastaccess for next checks + $USER->currentcourseaccess[$courseid] = $timenow; + if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; }; + + if ($exists) { // user_lastaccess record exists, update it + if ($db->Execute("UPDATE {$CFG->prefix}user_lastaccess + SET timeaccess = $timenow + WHERE userid = $USER->id AND courseid = $courseid")) { + } else { + debugging('Error: Could not update course user lastacess information'); // Don't throw an error + } + + } else { // user lastaccess record doesn't exist, insert it + if ($db->Execute("INSERT INTO {$CFG->prefix}user_lastaccess + (userid, courseid, timeaccess) + VALUES ($USER->id, $courseid, $timenow)")) { + } else { + debugging('Error: Could not insert course user lastaccess information'); // Don't throw an error + } } } } - /** * Select all log records based on SQL criteria * diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 4e19a143fb7..ddb5d4fb31d 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -1874,7 +1874,6 @@ function require_login($courseorid=0, $autologinguest=true, $cm=null) { } } - /// check whether the user should be changing password (but only if it is REALLY them) if (get_user_preferences('auth_forcepasswordchange') && empty($USER->realuser)) { $userauth = get_auth_plugin($USER->auth); @@ -1951,6 +1950,7 @@ function require_login($courseorid=0, $autologinguest=true, $cm=null) { && !has_capability('moodle/course:viewhiddenactivities', $COURSE->context)) { redirect($CFG->wwwroot, get_string('activityiscurrentlyhidden')); } + user_accesstime_log($COURSE->id); /// Access granted, update lastaccess times return; } else { @@ -1982,6 +1982,7 @@ function require_login($courseorid=0, $autologinguest=true, $cm=null) { if (has_capability('moodle/legacy:guest', $COURSE->context, NULL, false)) { if (has_capability('moodle/site:doanything', $sysctx)) { // administrators must be able to access any course - even if somebody gives them guest access + user_accesstime_log($COURSE->id); /// Access granted, update lastaccess times return; } @@ -1997,12 +1998,14 @@ function require_login($courseorid=0, $autologinguest=true, $cm=null) { get_string('activityiscurrentlyhidden')); } + user_accesstime_log($COURSE->id); /// Access granted, update lastaccess times return; // User is allowed to see this course break; case 2: /// Guests allowed with key if (!empty($USER->enrolkey[$COURSE->id])) { // Set by enrol/manual/enrol.php + user_accesstime_log($COURSE->id); /// Access granted, update lastaccess times return true; } // otherwise drop through to logic below (--> enrol.php) @@ -2038,6 +2041,7 @@ function require_login($courseorid=0, $autologinguest=true, $cm=null) { if (!empty($cm) and !$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $COURSE->context)) { redirect($CFG->wwwroot.'/course/view.php?id='.$cm->course, get_string('activityiscurrentlyhidden')); } + user_accesstime_log($COURSE->id); /// Access granted, update lastaccess times return; // User is allowed to see this course } @@ -2122,6 +2126,7 @@ function require_course_login($courseorid, $autologinguest=true, $cm=null) { } else if ((is_object($courseorid) and $courseorid->id == SITEID) or (!is_object($courseorid) and $courseorid == SITEID)) { //login for SITE not required + user_accesstime_log(SITEID); return; } else { @@ -3288,6 +3293,8 @@ function get_complete_user_data($field, $value, $mnethostid=null) { $user->preference = get_user_preferences(null, null, $user->id); + $user->lastcourseaccess = array(); // during last session + $user->currentcourseaccess = array(); // during current session if ($lastaccesses = get_records('user_lastaccess', 'userid', $user->id)) { foreach ($lastaccesses as $lastaccess) { $user->lastcourseaccess[$lastaccess->courseid] = $lastaccess->timeaccess;