MDL-29670 cron cleanup and minor fixing
Auth and enrol is moved to the top because other plugin types depend on accurate user list and enrolments. Passwords and failed login messages are generated during every cron execution. Contexts are build properly in each execution. Fixed deleting of unconfirmed users. And minor phpdocs and comments improvements.
This commit is contained in:
+380
-250
@@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@@ -24,6 +23,9 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Execute cron tasks
|
||||
*/
|
||||
function cron_run() {
|
||||
global $DB, $CFG, $OUTPUT;
|
||||
|
||||
@@ -51,26 +53,195 @@ function cron_run() {
|
||||
set_time_limit(0);
|
||||
$starttime = microtime();
|
||||
|
||||
/// increase memory limit
|
||||
// Increase memory limit
|
||||
raise_memory_limit(MEMORY_EXTRA);
|
||||
|
||||
/// emulate normal session
|
||||
// Emulate normal session - we use admin accoutn by default
|
||||
cron_setup_user();
|
||||
|
||||
/// Start output log
|
||||
|
||||
// Start output log
|
||||
$timenow = time();
|
||||
|
||||
mtrace("Server Time: ".date('r',$timenow)."\n\n");
|
||||
|
||||
|
||||
/// Session gc
|
||||
// Run cleanup core cron jobs, but not every time since they aren't too important.
|
||||
// These don't have a timer to reduce load, so we'll use a random number
|
||||
// to randomly choose the percentage of times we should run these jobs.
|
||||
srand ((double) microtime() * 10000000);
|
||||
$random100 = rand(0,100);
|
||||
if ($random100 < 20) { // Approximately 20% of the time.
|
||||
mtrace("Running clean-up tasks...");
|
||||
|
||||
mtrace("Cleaning up stale sessions");
|
||||
// Delete users who haven't confirmed within required period
|
||||
if (!empty($CFG->deleteunconfirmed)) {
|
||||
$cuttime = $timenow - ($CFG->deleteunconfirmed * 3600);
|
||||
$rs = $DB->get_recordset_sql ("SELECT *
|
||||
FROM {user}
|
||||
WHERE confirmed = 0 AND firstaccess > 0
|
||||
AND firstaccess < ?", array($cuttime));
|
||||
foreach ($rs as $user) {
|
||||
delete_user($user); // we MUST delete user properly first
|
||||
$DB->delete_records('user', array('id'=>$user->id)); // this is a bloody hack, but it might work
|
||||
mtrace(" Deleted unconfirmed user for ".fullname($user, true)." ($user->id)");
|
||||
}
|
||||
$rs->close();
|
||||
}
|
||||
|
||||
|
||||
// Delete users who haven't completed profile within required period
|
||||
if (!empty($CFG->deleteincompleteusers)) {
|
||||
$cuttime = $timenow - ($CFG->deleteincompleteusers * 3600);
|
||||
$rs = $DB->get_recordset_sql ("SELECT *
|
||||
FROM {user}
|
||||
WHERE confirmed = 1 AND lastaccess > 0
|
||||
AND lastaccess < ? AND deleted = 0
|
||||
AND (lastname = '' OR firstname = '' OR email = '')",
|
||||
array($cuttime));
|
||||
foreach ($rs as $user) {
|
||||
delete_user($user);
|
||||
mtrace(" Deleted not fully setup user $user->username ($user->id)");
|
||||
}
|
||||
$rs->close();
|
||||
}
|
||||
|
||||
|
||||
// Delete old logs to save space (this might need a timer to slow it down...)
|
||||
if (!empty($CFG->loglifetime)) { // value in days
|
||||
$loglifetime = $timenow - ($CFG->loglifetime * 3600 * 24);
|
||||
$DB->delete_records_select("log", "time < ?", array($loglifetime));
|
||||
mtrace(" Deleted old log records");
|
||||
}
|
||||
|
||||
|
||||
// Delete old backup_controllers and logs
|
||||
if (!empty($CFG->loglifetime)) { // value in days
|
||||
$loglifetime = $timenow - ($CFG->loglifetime * 3600 * 24);
|
||||
// Delete child records from backup_logs
|
||||
$DB->execute("DELETE FROM {backup_logs}
|
||||
WHERE EXISTS (
|
||||
SELECT 'x'
|
||||
FROM {backup_controllers} bc
|
||||
WHERE bc.backupid = {backup_logs}.backupid
|
||||
AND bc.timecreated < ?)", array($loglifetime));
|
||||
// Delete records from backup_controllers
|
||||
$DB->execute("DELETE FROM {backup_controllers}
|
||||
WHERE timecreated < ?", array($loglifetime));
|
||||
mtrace(" Deleted old backup records");
|
||||
}
|
||||
|
||||
|
||||
// Delete old cached texts
|
||||
if (!empty($CFG->cachetext)) { // Defined in config.php
|
||||
$cachelifetime = time() - $CFG->cachetext - 60; // Add an extra minute to allow for really heavy sites
|
||||
$DB->delete_records_select('cache_text', "timemodified < ?", array($cachelifetime));
|
||||
mtrace(" Deleted old cache_text records");
|
||||
}
|
||||
|
||||
|
||||
if (!empty($CFG->usetags)) {
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
tag_cron();
|
||||
mtrace(' Executed tag cron');
|
||||
}
|
||||
|
||||
|
||||
// Context maintenance stuff
|
||||
context_helper::cleanup_instances();
|
||||
mtrace(' Cleaned up context instances');
|
||||
context_helper::build_all_paths(false);
|
||||
// If you suspect that the context paths are somehow corrupt
|
||||
// replace the line below with: context_helper::build_all_paths(true);
|
||||
mtrace(' Built context paths');
|
||||
|
||||
|
||||
// Remove expired cache flags
|
||||
gc_cache_flags();
|
||||
mtrace(' Cleaned cache flags');
|
||||
|
||||
|
||||
// Cleanup messaging
|
||||
if (!empty($CFG->messagingdeletereadnotificationsdelay)) {
|
||||
$notificationdeletetime = time() - $CFG->messagingdeletereadnotificationsdelay;
|
||||
$DB->delete_records_select('message_read', 'notification=1 AND timeread<:notificationdeletetime', array('notificationdeletetime'=>$notificationdeletetime));
|
||||
mtrace(' Cleaned up read notifications');
|
||||
}
|
||||
|
||||
mtrace("...finished clean-up tasks");
|
||||
|
||||
} // End of occasional clean-up tasks
|
||||
|
||||
|
||||
// Send login failures notification - brute force protection in moodle is weak,
|
||||
// we should at least send notices early in each cron execution
|
||||
if (!empty($CFG->notifyloginfailures)) {
|
||||
notify_login_failures();
|
||||
mtrace(' Notified login failured');
|
||||
}
|
||||
|
||||
|
||||
// Make sure all context instances are properly created - they may be required in auth, enrol, etc.
|
||||
context_helper::create_instances();
|
||||
mtrace(' Created missing context instances');
|
||||
|
||||
|
||||
// Session gc
|
||||
session_gc();
|
||||
mtrace("Cleaned up stale user sessions");
|
||||
|
||||
/// Run all cron jobs for each module
|
||||
|
||||
// Run the auth cron, if any before enrolments
|
||||
// because it might add users that will be needed in enrol plugins
|
||||
$auths = get_enabled_auth_plugins();
|
||||
mtrace("Running auth crons if required...");
|
||||
foreach ($auths as $auth) {
|
||||
$authplugin = get_auth_plugin($auth);
|
||||
if (method_exists($authplugin, 'cron')) {
|
||||
mtrace("Running cron for auth/$auth...");
|
||||
$authplugin->cron();
|
||||
if (!empty($authplugin->log)) {
|
||||
mtrace($authplugin->log);
|
||||
}
|
||||
}
|
||||
unset($authplugin);
|
||||
}
|
||||
// Generate new password emails for users - ppl expect these generated asap
|
||||
if ($DB->count_records('user_preferences', array('name'=>'create_password', 'value'=>'1'))) {
|
||||
mtrace('Creating passwords for new users...');
|
||||
$newusers = $DB->get_recordset_sql("SELECT u.id as id, u.email, u.firstname,
|
||||
u.lastname, u.username,
|
||||
p.id as prefid
|
||||
FROM {user} u
|
||||
JOIN {user_preferences} p ON u.id=p.userid
|
||||
WHERE p.name='create_password' AND p.value='1' AND u.email !='' ");
|
||||
|
||||
foreach ($newusers as $newuser) {
|
||||
if (setnew_password_and_mail($newuser)) {
|
||||
unset_user_preference('create_password', $newuser);
|
||||
set_user_preference('auth_forcepasswordchange', 1, $newuser);
|
||||
} else {
|
||||
trigger_error("Could not create and mail new user password!");
|
||||
}
|
||||
}
|
||||
$newusers->close();
|
||||
}
|
||||
|
||||
|
||||
// It is very important to run enrol early
|
||||
// because other plugins depend on correct enrolment info.
|
||||
mtrace("Running enrol crons if required...");
|
||||
$enrols = enrol_get_plugins(true);
|
||||
foreach($enrols as $ename=>$enrol) {
|
||||
// do this for all plugins, disabled plugins might want to cleanup stuff such as roles
|
||||
if (!$enrol->is_cron_required()) {
|
||||
continue;
|
||||
}
|
||||
mtrace("Running cron for enrol_$ename...");
|
||||
$enrol->cron();
|
||||
$enrol->set_config('lastcron', time());
|
||||
}
|
||||
|
||||
|
||||
// Run all cron jobs for each module
|
||||
mtrace("Starting activity modules");
|
||||
get_mailer('buffer');
|
||||
if ($mods = $DB->get_records_select("modules", "cron > 0 AND ((? - lastcron) > cron) AND visible = 1", array($timenow))) {
|
||||
@@ -91,7 +262,7 @@ function cron_run() {
|
||||
mtrace("... used " . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries");
|
||||
mtrace("... used " . (microtime(1) - $pre_time) . " seconds");
|
||||
}
|
||||
/// Reset possible changes by modules to time_limit. MDL-11597
|
||||
// Reset possible changes by modules to time_limit. MDL-11597
|
||||
@set_time_limit(0);
|
||||
mtrace("done.");
|
||||
}
|
||||
@@ -101,9 +272,10 @@ function cron_run() {
|
||||
get_mailer('close');
|
||||
mtrace("Finished activity modules");
|
||||
|
||||
|
||||
mtrace("Starting blocks");
|
||||
if ($blocks = $DB->get_records_select("block", "cron > 0 AND ((? - lastcron) > cron) AND visible = 1", array($timenow))) {
|
||||
// we will need the base class.
|
||||
// We will need the base class.
|
||||
require_once($CFG->dirroot.'/blocks/moodleblock.class.php');
|
||||
foreach ($blocks as $block) {
|
||||
$blockfile = $CFG->dirroot.'/blocks/'.$block->name.'/block_'.$block->name.'.php';
|
||||
@@ -116,7 +288,7 @@ function cron_run() {
|
||||
if ($blockobj->cron()) {
|
||||
$DB->set_field('block', 'lastcron', $timenow, array('id'=>$block->id));
|
||||
}
|
||||
/// Reset possible changes by blocks to time_limit. MDL-11597
|
||||
// Reset possible changes by blocks to time_limit. MDL-11597
|
||||
@set_time_limit(0);
|
||||
mtrace('done.');
|
||||
}
|
||||
@@ -126,6 +298,8 @@ function cron_run() {
|
||||
}
|
||||
mtrace('Finished blocks');
|
||||
|
||||
|
||||
//TODO: get rid of this bloody hardcoded quiz module stuff, this must be done from quiz_cron()!
|
||||
mtrace("Starting quiz reports");
|
||||
if ($reports = $DB->get_records_select('quiz_reports', "cron > 0 AND ((? - lastcron) > cron)", array($timenow))) {
|
||||
foreach ($reports as $report) {
|
||||
@@ -152,11 +326,13 @@ function cron_run() {
|
||||
}
|
||||
mtrace("Finished quiz reports");
|
||||
|
||||
|
||||
mtrace('Starting admin reports');
|
||||
cron_execute_plugin_type('report');
|
||||
mtrace('Finished admin reports');
|
||||
|
||||
mtrace('Starting main gradebook job ...');
|
||||
|
||||
mtrace('Starting main gradebook job...');
|
||||
grade_cron();
|
||||
mtrace('done.');
|
||||
|
||||
@@ -183,189 +359,101 @@ function cron_run() {
|
||||
mtrace('done');
|
||||
}
|
||||
|
||||
|
||||
//now do plagiarism checks
|
||||
require_once($CFG->libdir.'/plagiarismlib.php');
|
||||
plagiarism_cron();
|
||||
|
||||
/// Run all core cron jobs, but not every time since they aren't too important.
|
||||
/// These don't have a timer to reduce load, so we'll use a random number
|
||||
/// to randomly choose the percentage of times we should run these jobs.
|
||||
|
||||
srand ((double) microtime() * 10000000);
|
||||
$random100 = rand(0,100);
|
||||
mtrace('Starting course reports');
|
||||
cron_execute_plugin_type('coursereport');
|
||||
mtrace('Finished course reports');
|
||||
|
||||
if ($random100 < 20) { // Approximately 20% of the time.
|
||||
mtrace("Running clean-up tasks...");
|
||||
|
||||
/// Delete users who haven't confirmed within required period
|
||||
// run gradebook import/export/report cron
|
||||
mtrace('Starting gradebook plugins');
|
||||
cron_execute_plugin_type('gradeimport');
|
||||
cron_execute_plugin_type('gradeexport');
|
||||
cron_execute_plugin_type('gradereport');
|
||||
mtrace('Finished gradebook plugins');
|
||||
|
||||
if (!empty($CFG->deleteunconfirmed)) {
|
||||
$cuttime = $timenow - ($CFG->deleteunconfirmed * 3600);
|
||||
$rs = $DB->get_recordset_sql ("SELECT id, firstname, lastname
|
||||
FROM {user}
|
||||
WHERE confirmed = 0 AND firstaccess > 0
|
||||
AND firstaccess < ?", array($cuttime));
|
||||
foreach ($rs as $user) {
|
||||
if ($DB->delete_records('user', array('id'=>$user->id))) {
|
||||
mtrace("Deleted unconfirmed user for ".fullname($user, true)." ($user->id)");
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
// Run external blog cron if needed
|
||||
if ($CFG->useexternalblogs) {
|
||||
require_once($CFG->dirroot . '/blog/lib.php');
|
||||
mtrace("Fetching external blog entries...", '');
|
||||
$sql = "timefetched < ? OR timefetched = 0";
|
||||
$externalblogs = $DB->get_records_select('blog_external', $sql, array(mktime() - $CFG->externalblogcrontime));
|
||||
|
||||
foreach ($externalblogs as $eb) {
|
||||
blog_sync_external_entries($eb);
|
||||
}
|
||||
flush();
|
||||
mtrace('done.');
|
||||
}
|
||||
// Run blog associations cleanup
|
||||
if ($CFG->useblogassociations) {
|
||||
require_once($CFG->dirroot . '/blog/lib.php');
|
||||
// delete entries whose contextids no longer exists
|
||||
mtrace("Deleting blog associations linked to non-existent contexts...", '');
|
||||
$DB->delete_records_select('blog_association', 'contextid NOT IN (SELECT id FROM {context})');
|
||||
mtrace('done.');
|
||||
}
|
||||
|
||||
|
||||
/// Delete users who haven't completed profile within required period
|
||||
|
||||
if (!empty($CFG->deleteincompleteusers)) {
|
||||
$cuttime = $timenow - ($CFG->deleteincompleteusers * 3600);
|
||||
$rs = $DB->get_recordset_sql ("SELECT *
|
||||
FROM {user}
|
||||
WHERE confirmed = 1 AND lastaccess > 0
|
||||
AND lastaccess < ? AND deleted = 0
|
||||
AND (lastname = '' OR firstname = '' OR email = '')",
|
||||
array($cuttime));
|
||||
foreach ($rs as $user) {
|
||||
if (delete_user($user)) {
|
||||
mtrace("Deleted not fully setup user $user->username ($user->id)");
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
}
|
||||
flush();
|
||||
//Run registration updated cron
|
||||
mtrace(get_string('siteupdatesstart', 'hub'));
|
||||
require_once($CFG->dirroot . '/admin/registration/lib.php');
|
||||
$registrationmanager = new registration_manager();
|
||||
$registrationmanager->cron();
|
||||
mtrace(get_string('siteupdatesend', 'hub'));
|
||||
|
||||
|
||||
/// Delete old logs to save space (this might need a timer to slow it down...)
|
||||
//cleanup old session linked tokens
|
||||
//deletes the session linked tokens that are over a day old.
|
||||
mtrace("Deleting session linked tokens more than one day old...", '');
|
||||
$DB->delete_records_select('external_tokens', 'lastaccess < :onedayago AND tokentype = :tokentype',
|
||||
array('onedayago' => time() - DAYSECS, 'tokentype' => EXTERNAL_TOKEN_EMBEDDED));
|
||||
mtrace('done.');
|
||||
|
||||
if (!empty($CFG->loglifetime)) { // value in days
|
||||
$loglifetime = $timenow - ($CFG->loglifetime * 3600 * 24);
|
||||
if ($DB->delete_records_select("log", "time < ?", array($loglifetime))) {
|
||||
mtrace("Deleted old log records");
|
||||
|
||||
// all other plugins
|
||||
cron_execute_plugin_type('message', 'message plugins');
|
||||
cron_execute_plugin_type('filter', 'filters');
|
||||
cron_execute_plugin_type('editor', 'editors');
|
||||
cron_execute_plugin_type('format', 'course formats');
|
||||
cron_execute_plugin_type('profilefield', 'profile fields');
|
||||
cron_execute_plugin_type('webservice', 'webservices');
|
||||
// TODO: Repository lib.php files are messed up (include many other files, etc), so it is
|
||||
// currently not possible to implement repository plugin cron using this infrastructure
|
||||
// cron_execute_plugin_type('repository', 'repository plugins');
|
||||
cron_execute_plugin_type('qtype', 'question types');
|
||||
cron_execute_plugin_type('plagiarism', 'plagiarism plugins');
|
||||
cron_execute_plugin_type('theme', 'themes');
|
||||
cron_execute_plugin_type('tool', 'admin tools');
|
||||
|
||||
|
||||
// and finally run any local cronjobs, if any
|
||||
if ($locals = get_plugin_list('local')) {
|
||||
mtrace('Processing customized cron scripts ...', '');
|
||||
// new cron functions in lib.php first
|
||||
cron_execute_plugin_type('local');
|
||||
// legacy cron files are executed directly
|
||||
foreach ($locals as $local => $localdir) {
|
||||
if (file_exists("$localdir/cron.php")) {
|
||||
include("$localdir/cron.php");
|
||||
}
|
||||
}
|
||||
flush();
|
||||
|
||||
// Delete old backup_controllers and logs
|
||||
|
||||
if (!empty($CFG->loglifetime)) { // value in days
|
||||
$loglifetime = $timenow - ($CFG->loglifetime * 3600 * 24);
|
||||
// Delete child records from backup_logs
|
||||
$DB->execute("DELETE FROM {backup_logs}
|
||||
WHERE EXISTS (
|
||||
SELECT 'x'
|
||||
FROM {backup_controllers} bc
|
||||
WHERE bc.backupid = {backup_logs}.backupid
|
||||
AND bc.timecreated < ?)", array($loglifetime));
|
||||
// Delete records from backup_controllers
|
||||
$DB->execute("DELETE FROM {backup_controllers}
|
||||
WHERE timecreated < ?", array($loglifetime));
|
||||
mtrace("Deleted old backup records");
|
||||
}
|
||||
flush();
|
||||
mtrace('done.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Delete old cached texts
|
||||
|
||||
if (!empty($CFG->cachetext)) { // Defined in config.php
|
||||
$cachelifetime = time() - $CFG->cachetext - 60; // Add an extra minute to allow for really heavy sites
|
||||
if ($DB->delete_records_select('cache_text', "timemodified < ?", array($cachelifetime))) {
|
||||
mtrace("Deleted old cache_text records");
|
||||
}
|
||||
}
|
||||
flush();
|
||||
|
||||
if (!empty($CFG->notifyloginfailures)) {
|
||||
notify_login_failures();
|
||||
mtrace('Notified login failured');
|
||||
}
|
||||
flush();
|
||||
|
||||
//
|
||||
// generate new password emails for users
|
||||
//
|
||||
mtrace('checking for create_password');
|
||||
if ($DB->count_records('user_preferences', array('name'=>'create_password', 'value'=>'1'))) {
|
||||
mtrace('creating passwords for new users');
|
||||
$newusers = $DB->get_recordset_sql("SELECT u.id as id, u.email, u.firstname,
|
||||
u.lastname, u.username,
|
||||
p.id as prefid
|
||||
FROM {user} u
|
||||
JOIN {user_preferences} p ON u.id=p.userid
|
||||
WHERE p.name='create_password' AND p.value='1' AND u.email !='' ");
|
||||
|
||||
foreach ($newusers as $newuser) {
|
||||
// email user
|
||||
if (setnew_password_and_mail($newuser)) {
|
||||
unset_user_preference('create_password', $newuser);
|
||||
set_user_preference('auth_forcepasswordchange', 1, $newuser);
|
||||
} else {
|
||||
trigger_error("Could not create and mail new user password!");
|
||||
}
|
||||
}
|
||||
$newusers->close();
|
||||
}
|
||||
|
||||
if (!empty($CFG->usetags)) {
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
tag_cron();
|
||||
mtrace ('Executed tag cron');
|
||||
}
|
||||
|
||||
// Accesslib stuff
|
||||
cleanup_contexts();
|
||||
mtrace ('Cleaned up contexts');
|
||||
gc_cache_flags();
|
||||
mtrace ('Cleaned cache flags');
|
||||
// If you suspect that the context paths are somehow corrupt
|
||||
// replace the line below with: build_context_path(true);
|
||||
build_context_path();
|
||||
mtrace ('Built context paths');
|
||||
|
||||
if (!empty($CFG->messagingdeletereadnotificationsdelay)) {
|
||||
$notificationdeletetime = time() - $CFG->messagingdeletereadnotificationsdelay;
|
||||
$DB->delete_records_select('message_read', 'notification=1 AND timeread<:notificationdeletetime', array('notificationdeletetime'=>$notificationdeletetime));
|
||||
mtrace('Cleaned up read notifications');
|
||||
}
|
||||
|
||||
mtrace("Finished clean-up tasks...");
|
||||
|
||||
} // End of occasional clean-up tasks
|
||||
|
||||
// Run automated backups if required.
|
||||
// Run automated backups if required - these may take a long time to execute
|
||||
require_once($CFG->dirroot.'/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot.'/backup/util/helper/backup_cron_helper.class.php');
|
||||
backup_cron_automated_helper::run_automated_backup();
|
||||
|
||||
/// Run the auth cron, if any
|
||||
/// before enrolments because it might add users that will be needed in enrol plugins
|
||||
$auths = get_enabled_auth_plugins();
|
||||
|
||||
mtrace("Running auth crons if required...");
|
||||
foreach ($auths as $auth) {
|
||||
$authplugin = get_auth_plugin($auth);
|
||||
if (method_exists($authplugin, 'cron')) {
|
||||
mtrace("Running cron for auth/$auth...");
|
||||
$authplugin->cron();
|
||||
if (!empty($authplugin->log)) {
|
||||
mtrace($authplugin->log);
|
||||
}
|
||||
}
|
||||
unset($authplugin);
|
||||
}
|
||||
|
||||
mtrace("Running enrol crons if required...");
|
||||
$enrols = enrol_get_plugins(true);
|
||||
foreach($enrols as $ename=>$enrol) {
|
||||
// do this for all plugins, disabled plugins might want to cleanup stuff such as roles
|
||||
if (!$enrol->is_cron_required()) {
|
||||
continue;
|
||||
}
|
||||
mtrace("Running cron for enrol_$ename...");
|
||||
$enrol->cron();
|
||||
$enrol->set_config('lastcron', time());
|
||||
}
|
||||
|
||||
// Run stats as at the end because they are known to take very long time on large sites
|
||||
if (!empty($CFG->enablestats) and empty($CFG->disablestatsprocessing)) {
|
||||
require_once($CFG->dirroot.'/lib/statslib.php');
|
||||
// check we're not before our runtime
|
||||
@@ -388,85 +476,10 @@ function cron_run() {
|
||||
}
|
||||
|
||||
|
||||
mtrace('Starting course reports');
|
||||
cron_execute_plugin_type('coursereport');
|
||||
mtrace('Finished course reports');
|
||||
|
||||
// run gradebook import/export/report cron
|
||||
mtrace('Starting gradebook plugins');
|
||||
cron_execute_plugin_type('gradeimport');
|
||||
cron_execute_plugin_type('gradeexport');
|
||||
cron_execute_plugin_type('gradereport');
|
||||
mtrace('Finished gradebook plugins');
|
||||
|
||||
// Run external blog cron if needed
|
||||
if ($CFG->useexternalblogs) {
|
||||
require_once($CFG->dirroot . '/blog/lib.php');
|
||||
mtrace("Fetching external blog entries...", '');
|
||||
$sql = "timefetched < ? OR timefetched = 0";
|
||||
$externalblogs = $DB->get_records_select('blog_external', $sql, array(mktime() - $CFG->externalblogcrontime));
|
||||
|
||||
foreach ($externalblogs as $eb) {
|
||||
blog_sync_external_entries($eb);
|
||||
}
|
||||
mtrace('done.');
|
||||
}
|
||||
|
||||
// Run blog associations cleanup
|
||||
if ($CFG->useblogassociations) {
|
||||
require_once($CFG->dirroot . '/blog/lib.php');
|
||||
// delete entries whose contextids no longer exists
|
||||
mtrace("Deleting blog associations linked to non-existent contexts...", '');
|
||||
$DB->delete_records_select('blog_association', 'contextid NOT IN (SELECT id FROM {context})');
|
||||
mtrace('done.');
|
||||
}
|
||||
|
||||
//Run registration updated cron
|
||||
mtrace(get_string('siteupdatesstart', 'hub'));
|
||||
require_once($CFG->dirroot . '/admin/registration/lib.php');
|
||||
$registrationmanager = new registration_manager();
|
||||
$registrationmanager->cron();
|
||||
mtrace(get_string('siteupdatesend', 'hub'));
|
||||
|
||||
// cleanup file trash
|
||||
// cleanup file trash - not very important
|
||||
$fs = get_file_storage();
|
||||
$fs->cron();
|
||||
|
||||
//cleanup old session linked tokens
|
||||
//deletes the session linked tokens that are over a day old.
|
||||
mtrace("Deleting session linked tokens more than one day old...", '');
|
||||
$DB->delete_records_select('external_tokens', 'lastaccess < :onedayago AND tokentype = :tokentype',
|
||||
array('onedayago' => time() - DAYSECS, 'tokentype' => EXTERNAL_TOKEN_EMBEDDED));
|
||||
mtrace('done.');
|
||||
|
||||
// all other plugins
|
||||
cron_execute_plugin_type('message', 'message plugins');
|
||||
cron_execute_plugin_type('filter', 'filters');
|
||||
cron_execute_plugin_type('editor', 'editors');
|
||||
cron_execute_plugin_type('format', 'course formats');
|
||||
cron_execute_plugin_type('profilefield', 'profile fields');
|
||||
cron_execute_plugin_type('webservice', 'webservices');
|
||||
// TODO: Repository lib.php files are messed up (include many other files, etc), so it is
|
||||
// currently not possible to implement repository plugin cron using this infrastructure
|
||||
// cron_execute_plugin_type('repository', 'repository plugins');
|
||||
cron_execute_plugin_type('qtype', 'question types');
|
||||
cron_execute_plugin_type('plagiarism', 'plagiarism plugins');
|
||||
cron_execute_plugin_type('theme', 'themes');
|
||||
cron_execute_plugin_type('tool', 'admin tools');
|
||||
|
||||
// and finally run any local cronjobs, if any
|
||||
if ($locals = get_plugin_list('local')) {
|
||||
mtrace('Processing customized cron scripts ...', '');
|
||||
// new cron functions in lib.php first
|
||||
cron_execute_plugin_type('local');
|
||||
// legacy cron files are executed directly
|
||||
foreach ($locals as $local => $localdir) {
|
||||
if (file_exists("$localdir/cron.php")) {
|
||||
include("$localdir/cron.php");
|
||||
}
|
||||
}
|
||||
mtrace('done.');
|
||||
}
|
||||
|
||||
mtrace("Cron script completed correctly");
|
||||
|
||||
@@ -476,6 +489,7 @@ function cron_run() {
|
||||
|
||||
/**
|
||||
* Executes cron functions for a specific type of plugin.
|
||||
*
|
||||
* @param string $plugintype Plugin type (e.g. 'report')
|
||||
* @param string $description If specified, will display 'Starting (whatever)'
|
||||
* and 'Finished (whatever)' lines, otherwise does not display
|
||||
@@ -541,6 +555,7 @@ function cron_execute_plugin_type($plugintype, $description = null) {
|
||||
* Used to add in old-style cron functions within plugins that have not been converted to the
|
||||
* new standard API. (The standard API is frankenstyle_name_cron() in lib.php; some types used
|
||||
* cron.php and some used a different name.)
|
||||
*
|
||||
* @param string $plugintype Plugin type e.g. 'report'
|
||||
* @param array $plugins Array from plugin name (e.g. 'report_frog') to function name (e.g.
|
||||
* 'report_frog_cron') for plugin cron functions that were already found using the new API
|
||||
@@ -595,4 +610,119 @@ function cron_bc_hack_plugin_functions($plugintype, $plugins) {
|
||||
}
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify admin users or admin user of any failed logins (since last notification).
|
||||
*
|
||||
* Note that this function must be only executed from the cron script
|
||||
* It uses the cache_flags system to store temporary records, deleting them
|
||||
* by name before finishing
|
||||
*/
|
||||
function notify_login_failures() {
|
||||
global $CFG, $DB, $OUTPUT;
|
||||
|
||||
$recip = get_users_from_config($CFG->notifyloginfailures, 'moodle/site:config');
|
||||
|
||||
if (empty($CFG->lastnotifyfailure)) {
|
||||
$CFG->lastnotifyfailure=0;
|
||||
}
|
||||
|
||||
// we need to deal with the threshold stuff first.
|
||||
if (empty($CFG->notifyloginthreshold)) {
|
||||
$CFG->notifyloginthreshold = 10; // default to something sensible.
|
||||
}
|
||||
|
||||
// Get all the IPs with more than notifyloginthreshold failures since lastnotifyfailure
|
||||
// and insert them into the cache_flags temp table
|
||||
$sql = "SELECT ip, COUNT(*)
|
||||
FROM {log}
|
||||
WHERE module = 'login' AND action = 'error'
|
||||
AND time > ?
|
||||
GROUP BY ip
|
||||
HAVING COUNT(*) >= ?";
|
||||
$params = array($CFG->lastnotifyfailure, $CFG->notifyloginthreshold);
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $iprec) {
|
||||
if (!empty($iprec->ip)) {
|
||||
set_cache_flag('login_failure_by_ip', $iprec->ip, '1', 0);
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
// Get all the INFOs with more than notifyloginthreshold failures since lastnotifyfailure
|
||||
// and insert them into the cache_flags temp table
|
||||
$sql = "SELECT info, count(*)
|
||||
FROM {log}
|
||||
WHERE module = 'login' AND action = 'error'
|
||||
AND time > ?
|
||||
GROUP BY info
|
||||
HAVING count(*) >= ?";
|
||||
$params = array($CFG->lastnotifyfailure, $CFG->notifyloginthreshold);
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $inforec) {
|
||||
if (!empty($inforec->info)) {
|
||||
set_cache_flag('login_failure_by_info', $inforec->info, '1', 0);
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
// Now, select all the login error logged records belonging to the ips and infos
|
||||
// since lastnotifyfailure, that we have stored in the cache_flags table
|
||||
$sql = "SELECT l.*, u.firstname, u.lastname
|
||||
FROM {log} l
|
||||
JOIN {cache_flags} cf ON l.ip = cf.name
|
||||
LEFT JOIN {user} u ON l.userid = u.id
|
||||
WHERE l.module = 'login' AND l.action = 'error'
|
||||
AND l.time > ?
|
||||
AND cf.flagtype = 'login_failure_by_ip'
|
||||
UNION ALL
|
||||
SELECT l.*, u.firstname, u.lastname
|
||||
FROM {log} l
|
||||
JOIN {cache_flags} cf ON l.info = cf.name
|
||||
LEFT JOIN {user} u ON l.userid = u.id
|
||||
WHERE l.module = 'login' AND l.action = 'error'
|
||||
AND l.time > ?
|
||||
AND cf.flagtype = 'login_failure_by_info'
|
||||
ORDER BY time DESC";
|
||||
$params = array($CFG->lastnotifyfailure, $CFG->lastnotifyfailure);
|
||||
|
||||
// Init some variables
|
||||
$count = 0;
|
||||
$messages = '';
|
||||
// Iterate over the logs recordset
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $log) {
|
||||
$log->time = userdate($log->time);
|
||||
$messages .= get_string('notifyloginfailuresmessage','',$log)."\n";
|
||||
$count++;
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
// If we haven't run in the last hour and
|
||||
// we have something useful to report and we
|
||||
// are actually supposed to be reporting to somebody
|
||||
if ((time() - HOURSECS) > $CFG->lastnotifyfailure && $count > 0 && is_array($recip) && count($recip) > 0) {
|
||||
$site = get_site();
|
||||
$subject = get_string('notifyloginfailuressubject', '', format_string($site->fullname));
|
||||
// Calculate the complete body of notification (start + messages + end)
|
||||
$body = get_string('notifyloginfailuresmessagestart', '', $CFG->wwwroot) .
|
||||
(($CFG->lastnotifyfailure != 0) ? '('.userdate($CFG->lastnotifyfailure).')' : '')."\n\n" .
|
||||
$messages .
|
||||
"\n\n".get_string('notifyloginfailuresmessageend','',$CFG->wwwroot)."\n\n";
|
||||
|
||||
// For each destination, send mail
|
||||
mtrace('Emailing admins about '. $count .' failed login attempts');
|
||||
foreach ($recip as $admin) {
|
||||
//emailing the admins directly rather than putting these through the messaging system
|
||||
email_to_user($admin,get_admin(), $subject, $body);
|
||||
}
|
||||
|
||||
// Update lastnotifyfailure with current time
|
||||
set_config('lastnotifyfailure', time());
|
||||
}
|
||||
|
||||
// Finally, delete all the temp records we have created in cache_flags
|
||||
$DB->delete_records_select('cache_flags', "flagtype IN ('login_failure_by_ip', 'login_failure_by_info')");
|
||||
}
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ function message_send($eventdata) {
|
||||
} else {
|
||||
//MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
|
||||
//exist in the message_provider table (thus there is no default settings for them)
|
||||
$preferrormsg = get_string('couldnotfindpreference', 'message', $preferencename);
|
||||
$preferrormsg = get_string('couldnotfindpreference', 'message', $preferencename); //TODO: undefined $preferencename
|
||||
throw new coding_exception($preferrormsg,'blah');
|
||||
}
|
||||
|
||||
|
||||
@@ -8320,124 +8320,6 @@ function upgrade_set_timeout($max_execution_time=300) {
|
||||
|
||||
/// MISCELLANEOUS ////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Notify admin users or admin user of any failed logins (since last notification).
|
||||
*
|
||||
* Note that this function must be only executed from the cron script
|
||||
* It uses the cache_flags system to store temporary records, deleting them
|
||||
* by name before finishing
|
||||
*
|
||||
* @global object
|
||||
* @global object
|
||||
* @uses HOURSECS
|
||||
*/
|
||||
function notify_login_failures() {
|
||||
global $CFG, $DB, $OUTPUT;
|
||||
|
||||
$recip = get_users_from_config($CFG->notifyloginfailures, 'moodle/site:config');
|
||||
|
||||
if (empty($CFG->lastnotifyfailure)) {
|
||||
$CFG->lastnotifyfailure=0;
|
||||
}
|
||||
|
||||
// we need to deal with the threshold stuff first.
|
||||
if (empty($CFG->notifyloginthreshold)) {
|
||||
$CFG->notifyloginthreshold = 10; // default to something sensible.
|
||||
}
|
||||
|
||||
/// Get all the IPs with more than notifyloginthreshold failures since lastnotifyfailure
|
||||
/// and insert them into the cache_flags temp table
|
||||
$sql = "SELECT ip, COUNT(*)
|
||||
FROM {log}
|
||||
WHERE module = 'login' AND action = 'error'
|
||||
AND time > ?
|
||||
GROUP BY ip
|
||||
HAVING COUNT(*) >= ?";
|
||||
$params = array($CFG->lastnotifyfailure, $CFG->notifyloginthreshold);
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $iprec) {
|
||||
if (!empty($iprec->ip)) {
|
||||
set_cache_flag('login_failure_by_ip', $iprec->ip, '1', 0);
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
/// Get all the INFOs with more than notifyloginthreshold failures since lastnotifyfailure
|
||||
/// and insert them into the cache_flags temp table
|
||||
$sql = "SELECT info, count(*)
|
||||
FROM {log}
|
||||
WHERE module = 'login' AND action = 'error'
|
||||
AND time > ?
|
||||
GROUP BY info
|
||||
HAVING count(*) >= ?";
|
||||
$params = array($CFG->lastnotifyfailure, $CFG->notifyloginthreshold);
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $inforec) {
|
||||
if (!empty($inforec->info)) {
|
||||
set_cache_flag('login_failure_by_info', $inforec->info, '1', 0);
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
/// Now, select all the login error logged records belonging to the ips and infos
|
||||
/// since lastnotifyfailure, that we have stored in the cache_flags table
|
||||
$sql = "SELECT l.*, u.firstname, u.lastname
|
||||
FROM {log} l
|
||||
JOIN {cache_flags} cf ON l.ip = cf.name
|
||||
LEFT JOIN {user} u ON l.userid = u.id
|
||||
WHERE l.module = 'login' AND l.action = 'error'
|
||||
AND l.time > ?
|
||||
AND cf.flagtype = 'login_failure_by_ip'
|
||||
UNION ALL
|
||||
SELECT l.*, u.firstname, u.lastname
|
||||
FROM {log} l
|
||||
JOIN {cache_flags} cf ON l.info = cf.name
|
||||
LEFT JOIN {user} u ON l.userid = u.id
|
||||
WHERE l.module = 'login' AND l.action = 'error'
|
||||
AND l.time > ?
|
||||
AND cf.flagtype = 'login_failure_by_info'
|
||||
ORDER BY time DESC";
|
||||
$params = array($CFG->lastnotifyfailure, $CFG->lastnotifyfailure);
|
||||
|
||||
/// Init some variables
|
||||
$count = 0;
|
||||
$messages = '';
|
||||
/// Iterate over the logs recordset
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $log) {
|
||||
$log->time = userdate($log->time);
|
||||
$messages .= get_string('notifyloginfailuresmessage','',$log)."\n";
|
||||
$count++;
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
/// If we haven't run in the last hour and
|
||||
/// we have something useful to report and we
|
||||
/// are actually supposed to be reporting to somebody
|
||||
if ((time() - HOURSECS) > $CFG->lastnotifyfailure && $count > 0 && is_array($recip) && count($recip) > 0) {
|
||||
$site = get_site();
|
||||
$subject = get_string('notifyloginfailuressubject', '', format_string($site->fullname));
|
||||
/// Calculate the complete body of notification (start + messages + end)
|
||||
$body = get_string('notifyloginfailuresmessagestart', '', $CFG->wwwroot) .
|
||||
(($CFG->lastnotifyfailure != 0) ? '('.userdate($CFG->lastnotifyfailure).')' : '')."\n\n" .
|
||||
$messages .
|
||||
"\n\n".get_string('notifyloginfailuresmessageend','',$CFG->wwwroot)."\n\n";
|
||||
|
||||
/// For each destination, send mail
|
||||
mtrace('Emailing admins about '. $count .' failed login attempts');
|
||||
foreach ($recip as $admin) {
|
||||
//emailing the admins directly rather than putting these through the messaging system
|
||||
email_to_user($admin,get_admin(), $subject, $body);
|
||||
}
|
||||
|
||||
/// Update lastnotifyfailure with current time
|
||||
set_config('lastnotifyfailure', time());
|
||||
}
|
||||
|
||||
/// Finally, delete all the temp records we have created in cache_flags
|
||||
$DB->delete_records_select('cache_flags', "flagtype IN ('login_failure_by_ip', 'login_failure_by_info')");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the system locale
|
||||
*
|
||||
|
||||
@@ -29,6 +29,7 @@ define ('MESSAGE_SHORTLENGTH', 300);
|
||||
|
||||
//$PAGE isnt set if we're being loaded by cron which doesnt display popups anyway
|
||||
if (isset($PAGE)) {
|
||||
//TODO: this is a mega crazy hack - it is not acceptable to call anything when including lib!!! (skodak)
|
||||
$PAGE->set_popup_notification_allowed(false); // We are in a message window (so don't pop up a new one)
|
||||
}
|
||||
|
||||
@@ -77,6 +78,7 @@ define('MESSAGE_PERMITTED_MASK', 0x0c); // 1100
|
||||
*/
|
||||
define('MESSAGE_DEFAULT_PERMITTED', 'permitted');
|
||||
|
||||
//TODO: defaults must be initialised via settings - this is a bad hack! (skodak)
|
||||
if (!isset($CFG->message_contacts_refresh)) { // Refresh the contacts list every 60 seconds
|
||||
$CFG->message_contacts_refresh = 60;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user