diff --git a/admin/cli/cron.php b/admin/cli/cron.php new file mode 100644 index 0000000000000..527aa7216432d --- /dev/null +++ b/admin/cli/cron.php @@ -0,0 +1,61 @@ +. + +/** + * CLI cron + * + * This script looks through all the module directories for cron.php files + * and runs them. These files can contain cleanup functions, email functions + * or anything that needs to be run on a regular basis. + * + * @package core + * @subpackage cli + * @copyright 2009 Petr Skoda (http://skodak.org) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define('CLI_SCRIPT', true); + +require(dirname(dirname(dirname(__FILE__))).'/config.php'); +require_once($CFG->libdir.'/clilib.php'); // cli only functions +require_once($CFG->libdir.'/cronlib.php'); + +// now get cli options +list($options, $unrecognized) = cli_get_params(array('help'=>false), + array('h'=>'help')); + +if ($unrecognized) { + $unrecognized = implode("\n ", $unrecognized); + cli_error(get_string('cliunknowoption', 'admin', $unrecognized)); +} + +if ($options['help']) { + $help = +"Execute periodic cron actions. + +Options: +-h, --help Print out this help + +Example: +\$sudo -u www-data /usr/bin/php admin/cli/cron.php +"; + + echo $help; + die; +} + +cron_run(); diff --git a/admin/cli/install.php b/admin/cli/install.php index 47caa9b2b5393..9f19c7d5cd4fc 100644 --- a/admin/cli/install.php +++ b/admin/cli/install.php @@ -30,9 +30,11 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +define('CLI_SCRIPT', true); + +// extra execution prevention - we can not just require config.php here if (isset($_SERVER['REMOTE_ADDR'])) { - error_log("admin/cli/install.php can not be called from web server!"); - exit; + exit(1); } $help = @@ -68,7 +70,8 @@ required in non-interactive mode. -h, --help Print out this help -Example: \$sudo -u wwwrun /usr/bin/php admin/cli/install.php --lang=cs +Example: +\$sudo -u www-data /usr/bin/php admin/cli/install.php --lang=cs "; //TODO: localize, mark as needed in install - to be translated later when everything is finished diff --git a/admin/cli/install_database.php b/admin/cli/install_database.php index 36335618c1d86..ad937283c27d2 100644 --- a/admin/cli/install_database.php +++ b/admin/cli/install_database.php @@ -28,9 +28,11 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +define('CLI_SCRIPT', true); + +// extra execution prevention - we can not just require config.php here if (isset($_SERVER['REMOTE_ADDR'])) { - error_log("admin/cli/install_database.php can not be called from web server!"); - exit; + exit(1); } $help = @@ -46,7 +48,8 @@ --agree-license Indicates agreement with software license. -h, --help Print out this help -Example: \$sudo -u wwwrun /usr/bin/php admin/cli/install_database.php --lang=cs --adminpass=soMePass123 --agree-license +Example: +\$sudo -u www-data /usr/bin/php admin/cli/install_database.php --lang=cs --adminpass=soMePass123 --agree-license "; // Check that PHP is of a sufficient version diff --git a/admin/cli/maintenance.php b/admin/cli/maintenance.php index dffbce032a449..01bfcc631ec40 100644 --- a/admin/cli/maintenance.php +++ b/admin/cli/maintenance.php @@ -24,12 +24,9 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -if (isset($_SERVER['REMOTE_ADDR'])) { - error_log("admin/cli/maintenance.php can not be called from web server!"); - exit; -} +define('CLI_SCRIPT', true); -require_once dirname(dirname(dirname(__FILE__))).'/config.php'; +require(dirname(dirname(dirname(__FILE__))).'/config.php'); require_once($CFG->libdir.'/clilib.php'); // cli only functions @@ -43,8 +40,7 @@ } if ($options['help']) { - -$help = + $help = "Maintenance mode settings. Current status displayed if not option specified. @@ -53,7 +49,8 @@ --disable Disable maintenance mode -h, --help Print out this help -Example: \$sudo -u wwwrun /usr/bin/php admin/cli/maintenance.php +Example: +\$sudo -u www-data /usr/bin/php admin/cli/maintenance.php "; //TODO: localize - to be translated later when everything is finished echo $help; diff --git a/admin/cli/reset_password.php b/admin/cli/reset_password.php index c9221c0ff0895..d7b4f74ed080b 100644 --- a/admin/cli/reset_password.php +++ b/admin/cli/reset_password.php @@ -24,12 +24,9 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -if (isset($_SERVER['REMOTE_ADDR'])) { - error_log("admin/cli/reset_password.php can not be called from web server!"); - exit; -} +define('CLI_SCRIPT', true); -require_once dirname(dirname(dirname(__FILE__))).'/config.php'; +require(dirname(dirname(dirname(__FILE__))).'/config.php'); require_once($CFG->libdir.'/clilib.php'); // cli only functions @@ -43,8 +40,7 @@ } if ($options['help']) { - -$help = + $help = "Reset local user passwords, useful especially for admin acounts. There are no security checks here because anybody who is able to @@ -53,7 +49,8 @@ Options: -h, --help Print out this help -Example: \$sudo -u wwwrun /usr/bin/php admin/cli/reset_password.php +Example: +\$sudo -u www-data /usr/bin/php admin/cli/reset_password.php "; //TODO: localize - to be translated later when everything is finished echo $help; @@ -79,6 +76,6 @@ $DB->set_field('user', 'password', $hashedpassword, array('id'=>$user->id)); -echo "Password cahnged\n"; +echo "Password changed\n"; exit(0); // 0 means success \ No newline at end of file diff --git a/admin/cli/upgrade.php b/admin/cli/upgrade.php index 95bc46f381538..e95e17df5c8e5 100644 --- a/admin/cli/upgrade.php +++ b/admin/cli/upgrade.php @@ -30,12 +30,9 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -if (isset($_SERVER['REMOTE_ADDR'])) { - error_log("admin/cli/upgrade.php can not be called from web server!"); - exit; -} +define('CLI_SCRIPT', true); -require_once dirname(dirname(dirname(__FILE__))).'/config.php'; +require(dirname(dirname(dirname(__FILE__))).'/config.php'); require_once($CFG->libdir.'/adminlib.php'); // various admin-only functions require_once($CFG->libdir.'/upgradelib.php'); // general upgrade/install related functions require_once($CFG->libdir.'/clilib.php'); // cli only functions @@ -54,8 +51,7 @@ } if ($options['help']) { - -$help = + $help = "Command line Moodle upgrade. Please note you must execute this script with the same uid as apache! @@ -65,7 +61,8 @@ --non-interactive No interactive questions or confirmations -h, --help Print out this help -Example: \$sudo -u wwwrun /usr/bin/php admin/cli/upgrade.php +Example: +\$sudo -u www-data /usr/bin/php admin/cli/upgrade.php "; //TODO: localize - to be translated later when everything is finished echo $help; diff --git a/admin/cron.php b/admin/cron.php index 6da148dd3a377..091d5b711bc93 100644 --- a/admin/cron.php +++ b/admin/cron.php @@ -1,534 +1,88 @@ admin/cropn.php" instead - //define('FULLME', 'cron'); - -/// Do not set moodle cookie because we do not need it here, it is better to emulate session - define('NO_MOODLE_COOKIES', true); - - require_once(dirname(__FILE__) . '/../config.php'); - require_once($CFG->libdir.'/adminlib.php'); - require_once($CFG->libdir.'/gradelib.php'); - -/// Extra debugging (set in config.php) - if (!empty($CFG->showcronsql)) { - $DB->set_debug(true); - } - if (!empty($CFG->showcrondebugging)) { - $CFG->debug = DEBUG_DEVELOPER; - $CFG->debugdisplay = true; - } - -/// extra safety - session_get_instance()->write_close(); - -/// check if execution allowed - if (isset($_SERVER['REMOTE_ADDR'])) { // if the script is accessed via the web. - if (!empty($CFG->cronclionly)) { - // This script can only be run via the cli. - print_error('cronerrorclionly', 'admin'); - exit; - } - // This script is being called via the web, so check the password if there is one. - if (!empty($CFG->cronremotepassword)) { - $pass = optional_param('password', '', PARAM_RAW); - if($pass != $CFG->cronremotepassword) { - // wrong password. - print_error('cronerrorpassword', 'admin'); - exit; - } - } - } - - -/// emulate normal session - cron_setup_user(); - -/// send mime type and encoding - if (check_browser_version('MSIE')) { - //ugly IE hack to work around downloading instead of viewing - @header('Content-Type: text/html; charset=utf-8'); - echo ""; //<pre> is not good enough for us here - } else { - //send proper plaintext header - @header('Content-Type: text/plain; charset=utf-8'); - } - -/// no more headers and buffers - while(@ob_end_flush()); - -/// increase memory limit (PHP 5.2 does different calculation, we need more memory now) - @raise_memory_limit('128M'); - -/// Start output log - - $timenow = time(); - - mtrace("Server Time: ".date('r',$timenow)."\n\n"); - - -/// Session gc - - mtrace("Cleaning up stale sessions"); - session_gc(); - -/// 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))) { - foreach ($mods as $mod) { - $libfile = "$CFG->dirroot/mod/$mod->name/lib.php"; - if (file_exists($libfile)) { - include_once($libfile); - $cron_function = $mod->name."_cron"; - if (function_exists($cron_function)) { - mtrace("Processing module function $cron_function ...", ''); - $pre_dbqueries = null; - $pre_dbqueries = $DB->perf_get_queries(); - $pre_time = microtime(1); - if ($cron_function()) { - if (!$DB->set_field("modules", "lastcron", $timenow, array("id"=>$mod->id))) { - mtrace("Error: could not update timestamp for $mod->fullname"); - } - } - if (isset($pre_dbqueries)) { - 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 - @set_time_limit(0); - mtrace("done."); - } - } - } - } - 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. - require_once($CFG->dirroot.'/blocks/moodleblock.class.php'); - foreach ($blocks as $block) { - $blockfile = $CFG->dirroot.'/blocks/'.$block->name.'/block_'.$block->name.'.php'; - if (file_exists($blockfile)) { - require_once($blockfile); - $classname = 'block_'.$block->name; - $blockobj = new $classname; - if (method_exists($blockobj,'cron')) { - mtrace("Processing cron function for ".$block->name.'....',''); - if ($blockobj->cron()) { - if (!$DB->set_field('block', 'lastcron', $timenow, array('id'=>$block->id))) { - mtrace('Error: could not update timestamp for '.$block->name); - } - } - /// Reset possible changes by blocks to time_limit. MDL-11597 - @set_time_limit(0); - mtrace('done.'); - } - } - - } - } - mtrace('Finished blocks'); - - mtrace("Starting quiz reports"); - if ($reports = $DB->get_records_select('quiz_report', "cron > 0 AND ((? - lastcron) > cron)", array($timenow))) { - foreach ($reports as $report) { - $cronfile = "$CFG->dirroot/mod/quiz/report/$report->name/cron.php"; - if (file_exists($cronfile)) { - include_once($cronfile); - $cron_function = 'quiz_report_'.$report->name."_cron"; - if (function_exists($cron_function)) { - mtrace("Processing quiz report cron function $cron_function ...", ''); - $pre_dbqueries = null; - $pre_dbqueries = $DB->perf_get_queries(); - $pre_time = microtime(1); - if ($cron_function()) { - if (!$DB->set_field('quiz_report', "lastcron", $timenow, array("id"=>$report->id))) { - mtrace("Error: could not update timestamp for $report->name"); - } - } - if (isset($pre_dbqueries)) { - mtrace("... used " . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries"); - mtrace("... used " . (microtime(1) - $pre_time) . " seconds"); - } - mtrace("done."); - } - } - } - } - mtrace("Finished quiz reports"); - - mtrace('Starting admin reports'); - // Admin reports do not have a database table that lists them. Instead a - // report includes cron.php with function report_reportname_cron() if it wishes - // to be cronned. It is up to cron.php to handle e.g. if it only needs to - // actually do anything occasionally. - $reports = get_plugin_list('report'); - foreach($reports as $report => $reportdir) { - $cronfile = $reportdir.'/cron.php'; - if (file_exists($cronfile)) { - require_once($cronfile); - $cronfunction = 'report_'.$report.'_cron'; - mtrace('Processing cron function for '.$report.'...', ''); - $pre_dbqueries = null; - $pre_dbqueries = $DB->perf_get_queries(); - $pre_time = microtime(true); - $cronfunction(); - if (isset($pre_dbqueries)) { - mtrace("... used " . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries"); - mtrace("... used " . round(microtime(true) - $pre_time, 2) . " seconds"); - } - mtrace('done.'); - } - } - mtrace('Finished admin reports'); - - mtrace('Starting main gradebook job ...'); - grade_cron(); - mtrace('done.'); - - - mtrace('Starting processing the event queue...'); - events_cron(); - mtrace('done.'); - - - if ($CFG->enablecompletion) { - // Completion cron - mtrace('Starting the completion cron...'); - require_once($CFG->libdir . '/completion/cron.php'); - completion_cron(); - mtrace('done'); - } - - - if ($CFG->enableportfolios) { - // Portfolio cron - mtrace('Starting the portfolio cron...'); - require_once($CFG->libdir . '/portfoliolib.php'); - portfolio_cron(); - mtrace('done'); - } - -/// 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); - - if ($random100 < 20) { // Approximately 20% of the time. - mtrace("Running clean-up tasks..."); - - /// Delete users who haven't confirmed within required period - - 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(); - } - flush(); - - - /// 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 id, username - 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(); - - - /// 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); - if ($DB->delete_records_select("log", "time < ?", array($loglifetime))) { - mtrace("Deleted old log records"); - } - } - flush(); - - - /// 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_records_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 $newuserid => $newuser) { - $newuser->emailstop = 0; // send email regardless - // email user - if (setnew_password_and_mail($newuser)) { - // remove user pref - $DB->delete_records('user_preferences', array('id'=>$newuser->prefid)); - } else { - trigger_error("Could not create and mail new user password!"); - } - } - } - - 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'); - - mtrace("Finished clean-up tasks..."); - - } // End of occasional clean-up tasks - - // Disabled until implemented. MDL-21432, MDL-22184 - if (1 == 2 && empty($CFG->disablescheduledbackups)) { // Defined in config.php - //Execute backup's cron - //Perhaps a long time and memory could help in large sites - @set_time_limit(0); - @raise_memory_limit("192M"); - if (function_exists('apache_child_terminate')) { - // if we are running from Apache, give httpd a hint that - // it can recycle the process after it's done. Apache's - // memory management is truly awful but we can help it. - @apache_child_terminate(); - } - if (file_exists("$CFG->dirroot/backup/backup_scheduled.php") and - file_exists("$CFG->dirroot/backup/backuplib.php") and - file_exists("$CFG->dirroot/backup/lib.php") and - file_exists("$CFG->libdir/blocklib.php")) { - include_once("$CFG->dirroot/backup/backup_scheduled.php"); - include_once("$CFG->dirroot/backup/backuplib.php"); - include_once("$CFG->dirroot/backup/lib.php"); - mtrace("Running backups if required..."); - - if (! schedule_backup_cron()) { - mtrace("ERROR: Something went wrong while performing backup tasks!!!"); - } else { - mtrace("Backup tasks finished."); - } - } - } - -/// 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()); - } - - if (!empty($CFG->enablestats) and empty($CFG->disablestatsprocessing)) { - require_once($CFG->dirroot.'/lib/statslib.php'); - // check we're not before our runtime - $timetocheck = stats_get_base_daily() + $CFG->statsruntimestarthour*60*60 + $CFG->statsruntimestartminute*60; - - if (time() > $timetocheck) { - // process configured number of days as max (defaulting to 31) - $maxdays = empty($CFG->statsruntimedays) ? 31 : abs($CFG->statsruntimedays); - if (stats_cron_daily($maxdays)) { - if (stats_cron_weekly()) { - if (stats_cron_monthly()) { - stats_clean_old(); - } - } - } - @set_time_limit(0); - } else { - mtrace('Next stats run after:'. userdate($timetocheck)); - } - } - - // run gradebook import/export/report cron - if ($gradeimports = get_plugin_list('gradeimport')) { - foreach ($gradeimports as $gradeimport => $plugindir) { - if (file_exists($plugindir.'/lib.php')) { - require_once($plugindir.'/lib.php'); - $cron_function = 'grade_import_'.$gradeimport.'_cron'; - if (function_exists($cron_function)) { - mtrace("Processing gradebook import function $cron_function ...", ''); - $cron_function(); - } - } - } - } - - if ($gradeexports = get_plugin_list('gradeexport')) { - foreach ($gradeexports as $gradeexport => $plugindir) { - if (file_exists($plugindir.'/lib.php')) { - require_once($plugindir.'/lib.php'); - $cron_function = 'grade_export_'.$gradeexport.'_cron'; - if (function_exists($cron_function)) { - mtrace("Processing gradebook export function $cron_function ...", ''); - $cron_function(); - } - } - } - } - - if ($gradereports = get_plugin_list('gradereport')) { - foreach ($gradereports as $gradereport => $plugindir) { - if (file_exists($plugindir.'/lib.php')) { - require_once($plugindir.'/lib.php'); - $cron_function = 'grade_report_'.$gradereport.'_cron'; - if (function_exists($cron_function)) { - mtrace("Processing gradebook report function $cron_function ...", ''); - $cron_function(); - } - } - } - } - - // 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); - } - } - - // 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})'); - } - - //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 - $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.'); - - // run any customized cronjobs, if any - if ($locals = get_plugin_list('local')) { - mtrace('Processing customized cron scripts ...', ''); - foreach ($locals as $local => $localdir) { - if (file_exists("$localdir/cron.php")) { - include("$localdir/cron.php"); - } - } - mtrace('done.'); - } - - - mtrace("Cron script completed correctly"); - - $difftime = microtime_diff($starttime, microtime()); - mtrace("Execution took ".$difftime." seconds"); - -/// finish the IE hack - if (check_browser_version('MSIE')) { - echo ""; - } +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Web cron + * + * This script looks through all the module directories for cron.php files + * and runs them. These files can contain cleanup functions, email functions + * or anything that needs to be run on a regular basis. + * + * This file is best run from cron on the host system (ie outside PHP). + * It is strongly recommended to add password protection via admin settings. + * + * eg wget -q -O /dev/null 'http: *moodle.somewhere.edu/admin/cron.php?password=SeCreT666' + * + * It is also possible to use CLI script admin/cli/cron.php instead, + * you can not call this script from command line any more. + * + * @package core + * @subpackage admin + * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +// This is a fake CLI script, it is a really ugly hack which emulates +// CLI via web interface, please do not use this hack elsewhere +define('CLI_SCRIPT', true); +define('WEB_CRON_EMULATED_CLI', 'defined'); // ugly ugly hack, do not use elsewhere please + +require('../config.php'); +require_once($CFG->libdir.'/clilib.php'); +require_once($CFG->libdir.'/cronlib.php'); + +// extra safety +session_get_instance()->write_close(); + +// check if execution allowed +if (!empty($CFG->cronclionly)) { + // This script can only be run via the cli. + print_error('cronerrorclionly', 'admin'); + exit; +} +// This script is being called via the web, so check the password if there is one. +if (!empty($CFG->cronremotepassword)) { + $pass = optional_param('password', '', PARAM_RAW); + if ($pass != $CFG->cronremotepassword) { + // wrong password. + print_error('cronerrorpassword', 'admin'); + exit; + } +} + +// send mime type and encoding +if (check_browser_version('MSIE')) { + //ugly IE hack to work around downloading instead of viewing + @header('Content-Type: text/html; charset=utf-8'); + echo ""; //<pre> is not good enough for us here +} else { + //send proper plaintext header + @header('Content-Type: text/plain; charset=utf-8'); +} + +// no more headers and buffers +while(@ob_end_flush()); + +// execute the cron +cron_run(); + +// finish the IE hack +if (check_browser_version('MSIE')) { + echo ""; +} diff --git a/auth/cas/cas_ldap_sync_users.php b/auth/cas/cas_ldap_sync_users.php deleted file mode 100644 index 181d5a8a96534..0000000000000 --- a/auth/cas/cas_ldap_sync_users.php +++ /dev/null @@ -1,44 +0,0 @@ -dirroot.'/course/lib.php'); - -// Ensure errors are well explained -$CFG->debug = DEBUG_NORMAL; - -if (!is_enabled_auth('cas')) { - error_log('[AUTH CAS] '.get_string('pluginnotenabled', 'auth_ldap')); - die; -} - -$casauth = get_auth_plugin('cas'); -$casauth->sync_users(true); - diff --git a/auth/cas/cli/sync_users.php b/auth/cas/cli/sync_users.php new file mode 100644 index 0000000000000..0369963eec0ca --- /dev/null +++ b/auth/cas/cli/sync_users.php @@ -0,0 +1,62 @@ +. + +/** + * CAS user sync script. + * + * This script is meant to be called from a cronjob to sync moodle with the CAS + * backend in those setups where the CAS backend acts as 'master'. + * + * Sample cron entry: + * # 5 minutes past 4am + * 5 4 * * * $sudo -u www-data /usr/bin/php /var/www/moodle/auth/cas/cli/sync_users.php + * + * Notes: + * - it is required to use the web server account when executing PHP CLI scripts + * - you need to change the "www-data" to match the apache user account + * - use "su" if "sudo" not available + * - If you have a large number of users, you may want to raise the memory limits + * by passing -d momory_limit=256M + * - For debugging & better logging, you are encouraged to use in the command line: + * -d log_errors=1 -d error_reporting=E_ALL -d display_errors=0 -d html_errors=0 + * + * Performance notes: + * We have optimized it as best as we could for PostgreSQL and MySQL, with 27K students + * we have seen this take 10 minutes. + * + * @package auth + * @subpackage CAS + * @copyright 2007 Jerome Gutierrez - based on code by Martin Langhoff + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define('CLI_SCRIPT', true); + +require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php'); +require_once($CFG->dirroot.'/course/lib.php'); + +// Ensure errors are well explained +$CFG->debug = DEBUG_NORMAL; + +if (!is_enabled_auth('cas')) { + error_log('[AUTH CAS] '.get_string('pluginnotenabled', 'auth_ldap')); + die; +} + +$casauth = get_auth_plugin('cas'); +$casauth->sync_users(true); + diff --git a/auth/db/auth_db_sync_users.php b/auth/db/auth_db_sync_users.php deleted file mode 100644 index 8a7f0addbd676..0000000000000 --- a/auth/db/auth_db_sync_users.php +++ /dev/null @@ -1,43 +0,0 @@ -dirroot.'/course/lib.php'); - -if (!is_enabled_auth('db')) { - echo "Plugin not enabled!"; - die; -} - -$dbauth = get_auth_plugin('db'); -$dbauth->sync_users(true); - diff --git a/auth/db/cli/sync_users.php b/auth/db/cli/sync_users.php new file mode 100644 index 0000000000000..5863592f54690 --- /dev/null +++ b/auth/db/cli/sync_users.php @@ -0,0 +1,59 @@ +. + +/** + * Extdb user sync script. + * + * This script is meant to be called from a system cronjob to + * sync moodle user accounts with external database. + * It is required when using internal passwords (== passwords not defined in external database). + * + * Sample cron entry: + * # 5 minutes past 4am + * 5 4 * * * $sudo -u www-data /usr/bin/php /var/www/moodle/auth/db/cli/sync_users.php + * + * Notes: + * - it is required to use the web server account when executing PHP CLI scripts + * - you need to change the "www-data" to match the apache user account + * - use "su" if "sudo" not available + * - If you have a large number of users, you may want to raise the memory limits + * by passing -d memory_limit=256M + * - For debugging & better logging, you are encouraged to use in the command line: + * -d log_errors=1 -d error_reporting=E_ALL -d display_errors=0 -d html_errors=0 + * + * Performance notes: + * + The code is simpler, but not as optimized as its LDAP counterpart. + * + * @package auth + * @subpackage db + * @copyright 2006 Martin Langhoff + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define('CLI_SCRIPT', true); + +require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php'); +require_once($CFG->dirroot.'/course/lib.php'); + +if (!is_enabled_auth('db')) { + echo "Plugin not enabled!"; + die; +} + +$dbauth = get_auth_plugin('db'); +$dbauth->sync_users(true); + diff --git a/auth/ldap/auth_ldap_sync_users.php b/auth/ldap/auth_ldap_sync_users.php deleted file mode 100755 index 3dc251e1fe566..0000000000000 --- a/auth/ldap/auth_ldap_sync_users.php +++ /dev/null @@ -1,43 +0,0 @@ -dirroot.'/course/lib.php'); - -// Ensure errors are well explained -$CFG->debug = DEBUG_NORMAL; - -if (!is_enabled_auth('ldap')) { - error_log('[AUTH LDAP] '.get_string('pluginnotenabled', 'auth_ldap')); - die; -} - -$ldapauth = get_auth_plugin('ldap'); -$ldapauth->sync_users(true); - diff --git a/auth/ldap/cli/sync_users.php b/auth/ldap/cli/sync_users.php new file mode 100755 index 0000000000000..57637cac1e798 --- /dev/null +++ b/auth/ldap/cli/sync_users.php @@ -0,0 +1,66 @@ +. + +/** + * CAS user sync script. + * + * This script is meant to be called from a cronjob to sync moodle with the LDAP + * backend in those setups where the LDAP backend acts as 'master'. + * + * Sample cron entry: + * # 5 minutes past 4am + * 5 4 * * * $sudo -u www-data /usr/bin/php /var/www/moodle/auth/ldap/cli/sync_users.php + * + * Notes: + * - it is required to use the web server account when executing PHP CLI scripts + * - you need to change the "www-data" to match the apache user account + * - use "su" if "sudo" not available + * - If you have a large number of users, you may want to raise the memory limits + * by passing -d momory_limit=256M + * - For debugging & better logging, you are encouraged to use in the command line: + * -d log_errors=1 -d error_reporting=E_ALL -d display_errors=0 -d html_errors=0 + * - If you have a large number of users, you may want to raise the memory limits + * by passing -d momory_limit=256M + * - For debugging & better logging, you are encouraged to use in the command line: + * -d log_errors=1 -d error_reporting=E_ALL -d display_errors=0 -d html_errors=0 + * + * Performance notes: + * We have optimized it as best as we could for PostgreSQL and MySQL, with 27K students + * we have seen this take 10 minutes. + * + * @package auth + * @subpackage ldap + * @copyright 2004 Martin Langhoff + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define('CLI_SCRIPT', true); + +require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php'); // global moodle config file. +require_once($CFG->dirroot.'/course/lib.php'); + +// Ensure errors are well explained +$CFG->debug = DEBUG_NORMAL; + +if (!is_enabled_auth('ldap')) { + error_log('[AUTH LDAP] '.get_string('pluginnotenabled', 'auth_ldap')); + die; +} + +$ldapauth = get_auth_plugin('ldap'); +$ldapauth->sync_users(true); + diff --git a/enrol/category/cli/sync.php b/enrol/category/cli/sync.php index 6367bb10ae057..47b1e37477e84 100644 --- a/enrol/category/cli/sync.php +++ b/enrol/category/cli/sync.php @@ -18,16 +18,21 @@ /** * CLI sync for full category enrol synchronisation. * + * Sample execution: + * $sudo -u www-data /usr/bin/php /var/www/moodle/enrol/category/cli/sync.php + * + * Notes: + * - it is required to use the web server account when executing PHP CLI scripts + * - you need to change the "www-data" to match the apache user account + * - use "su" if "sudo" not available + * * @package enrol * @subpackage category * @copyright 2010 Petr Skoda {@link http://skodak.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -if (isset($_SERVER['REMOTE_ADDR'])) { - error_log("enrol/category/cli/sync.php can not be called from web server!"); - exit; -} +define('CLI_SCRIPT', true); require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php'); require_once("$CFG->dirroot/enrol/category/locallib.php"); diff --git a/enrol/database/cli/sync.php b/enrol/database/cli/sync.php index 00c699b7868ca..79af47da48c5d 100644 --- a/enrol/database/cli/sync.php +++ b/enrol/database/cli/sync.php @@ -18,16 +18,22 @@ /** * CLI sync for full external database synchronisation. * + * Sample cron entry: + * # 5 minutes past 4am + * 5 4 * * * $sudo -u www-data /usr/bin/php /var/www/moodle/enrol/database/cli/sync.php + * + * Notes: + * - it is required to use the web server account when executing PHP CLI scripts + * - you need to change the "www-data" to match the apache user account + * - use "su" if "sudo" not available + * * @package enrol * @subpackage database * @copyright 2010 Petr Skoda {@link http://skodak.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -if (isset($_SERVER['REMOTE_ADDR'])) { - error_log("enrol/database/cli/sync.php can not be called from web server!"); - exit; -} +define('CLI_SCRIPT', true); require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php'); diff --git a/enrol/ldap/cli/sync.php b/enrol/ldap/cli/sync.php index 2a58be5c56138..d9fb913b58d40 100644 --- a/enrol/ldap/cli/sync.php +++ b/enrol/ldap/cli/sync.php @@ -17,39 +17,34 @@ /** * CLI sync for full LDAP synchronisation. - * - * @package enrol - * @subpackage ldap - * @author Iñaki Arenaza - based on code by Martin Dougiamas, Martin Langhoff and others - * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} - * @copyright 2010 Iñaki Arenaza - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** * * This script is meant to be called from a cronjob to sync moodle with the LDAP * backend in those setups where the LDAP backend acts as 'master' for enrolment. * - * Example cron entry: + * Sample cron entry: * # 5 minutes past 4am - * 5 4 * * * /usr/bin/php5 -c /etc/php5/cli/php.ini /var/www/moodle/enrol/ldap/cli/sync.php + * 5 4 * * * $sudo -u www-data /usr/bin/php /var/www/moodle/enrol/ldap/cli/sync.php * * Notes: + * - it is required to use the web server account when executing PHP CLI scripts + * - you need to change the "www-data" to match the apache user account + * - use "su" if "sudo" not available * - If you have a large number of users, you may want to raise the memory limits * by passing -d momory_limit=256M * - For debugging & better logging, you are encouraged to use in the command line: * -d log_errors=1 -d error_reporting=E_ALL -d display_errors=0 -d html_errors=0 * + * @package enrol + * @subpackage ldap + * @author Iñaki Arenaza - based on code by Martin Dougiamas, Martin Langhoff and others + * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} + * @copyright 2010 Iñaki Arenaza + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -if (isset($_SERVER['REMOTE_ADDR'])) { - error_log("enrol/ldap/cli/sync.php can not be called from web server!"); - echo "enrol/ldap/cli/sync.php can not be called from web server!"; - exit; -} +define('CLI_SCRIPT', true); -require_once(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php'); +require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php'); // Ensure errors are well explained $CFG->debug = DEBUG_NORMAL; diff --git a/lib/cronlib.php b/lib/cronlib.php new file mode 100644 index 0000000000000..c71d742a92a81 --- /dev/null +++ b/lib/cronlib.php @@ -0,0 +1,497 @@ +. + +/** + * Cron functions. + * + * @package core + * @subpackage admin + * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +function cron_run() { + global $DB, $CFG, $OUTPUT; + + require_once($CFG->libdir.'/adminlib.php'); + require_once($CFG->libdir.'/gradelib.php'); + + if (!empty($CFG->showcronsql)) { + $DB->set_debug(true); + } + if (!empty($CFG->showcrondebugging)) { + $CFG->debug = DEBUG_DEVELOPER; + $CFG->debugdisplay = true; + } + + set_time_limit(0); + $starttime = microtime(); + +/// increase memory limit (PHP 5.2 does different calculation, we need more memory now) + @raise_memory_limit('128M'); + +/// emulate normal session + cron_setup_user(); + +/// Start output log + + $timenow = time(); + + mtrace("Server Time: ".date('r',$timenow)."\n\n"); + + +/// Session gc + + mtrace("Cleaning up stale sessions"); + session_gc(); + +/// 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))) { + foreach ($mods as $mod) { + $libfile = "$CFG->dirroot/mod/$mod->name/lib.php"; + if (file_exists($libfile)) { + include_once($libfile); + $cron_function = $mod->name."_cron"; + if (function_exists($cron_function)) { + mtrace("Processing module function $cron_function ...", ''); + $pre_dbqueries = null; + $pre_dbqueries = $DB->perf_get_queries(); + $pre_time = microtime(1); + if ($cron_function()) { + if (!$DB->set_field("modules", "lastcron", $timenow, array("id"=>$mod->id))) { + mtrace("Error: could not update timestamp for $mod->fullname"); + } + } + if (isset($pre_dbqueries)) { + 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 + @set_time_limit(0); + mtrace("done."); + } + } + } + } + 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. + require_once($CFG->dirroot.'/blocks/moodleblock.class.php'); + foreach ($blocks as $block) { + $blockfile = $CFG->dirroot.'/blocks/'.$block->name.'/block_'.$block->name.'.php'; + if (file_exists($blockfile)) { + require_once($blockfile); + $classname = 'block_'.$block->name; + $blockobj = new $classname; + if (method_exists($blockobj,'cron')) { + mtrace("Processing cron function for ".$block->name.'....',''); + if ($blockobj->cron()) { + if (!$DB->set_field('block', 'lastcron', $timenow, array('id'=>$block->id))) { + mtrace('Error: could not update timestamp for '.$block->name); + } + } + /// Reset possible changes by blocks to time_limit. MDL-11597 + @set_time_limit(0); + mtrace('done.'); + } + } + + } + } + mtrace('Finished blocks'); + + mtrace("Starting quiz reports"); + if ($reports = $DB->get_records_select('quiz_report', "cron > 0 AND ((? - lastcron) > cron)", array($timenow))) { + foreach ($reports as $report) { + $cronfile = "$CFG->dirroot/mod/quiz/report/$report->name/cron.php"; + if (file_exists($cronfile)) { + include_once($cronfile); + $cron_function = 'quiz_report_'.$report->name."_cron"; + if (function_exists($cron_function)) { + mtrace("Processing quiz report cron function $cron_function ...", ''); + $pre_dbqueries = null; + $pre_dbqueries = $DB->perf_get_queries(); + $pre_time = microtime(1); + if ($cron_function()) { + if (!$DB->set_field('quiz_report', "lastcron", $timenow, array("id"=>$report->id))) { + mtrace("Error: could not update timestamp for $report->name"); + } + } + if (isset($pre_dbqueries)) { + mtrace("... used " . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries"); + mtrace("... used " . (microtime(1) - $pre_time) . " seconds"); + } + mtrace("done."); + } + } + } + } + mtrace("Finished quiz reports"); + + mtrace('Starting admin reports'); + // Admin reports do not have a database table that lists them. Instead a + // report includes cron.php with function report_reportname_cron() if it wishes + // to be cronned. It is up to cron.php to handle e.g. if it only needs to + // actually do anything occasionally. + $reports = get_plugin_list('report'); + foreach($reports as $report => $reportdir) { + $cronfile = $reportdir.'/cron.php'; + if (file_exists($cronfile)) { + require_once($cronfile); + $cronfunction = 'report_'.$report.'_cron'; + mtrace('Processing cron function for '.$report.'...', ''); + $pre_dbqueries = null; + $pre_dbqueries = $DB->perf_get_queries(); + $pre_time = microtime(true); + $cronfunction(); + if (isset($pre_dbqueries)) { + mtrace("... used " . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries"); + mtrace("... used " . round(microtime(true) - $pre_time, 2) . " seconds"); + } + mtrace('done.'); + } + } + mtrace('Finished admin reports'); + + mtrace('Starting main gradebook job ...'); + grade_cron(); + mtrace('done.'); + + + mtrace('Starting processing the event queue...'); + events_cron(); + mtrace('done.'); + + + if ($CFG->enablecompletion) { + // Completion cron + mtrace('Starting the completion cron...'); + require_once($CFG->libdir . '/completion/cron.php'); + completion_cron(); + mtrace('done'); + } + + + if ($CFG->enableportfolios) { + // Portfolio cron + mtrace('Starting the portfolio cron...'); + require_once($CFG->libdir . '/portfoliolib.php'); + portfolio_cron(); + mtrace('done'); + } + +/// 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); + + if ($random100 < 20) { // Approximately 20% of the time. + mtrace("Running clean-up tasks..."); + + /// Delete users who haven't confirmed within required period + + 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(); + } + flush(); + + + /// 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 id, username + 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(); + + + /// 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); + if ($DB->delete_records_select("log", "time < ?", array($loglifetime))) { + mtrace("Deleted old log records"); + } + } + flush(); + + + /// 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_records_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 $newuserid => $newuser) { + $newuser->emailstop = 0; // send email regardless + // email user + if (setnew_password_and_mail($newuser)) { + // remove user pref + $DB->delete_records('user_preferences', array('id'=>$newuser->prefid)); + } else { + trigger_error("Could not create and mail new user password!"); + } + } + } + + 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'); + + mtrace("Finished clean-up tasks..."); + + } // End of occasional clean-up tasks + + // Disabled until implemented. MDL-21432, MDL-22184 + if (1 == 2 && empty($CFG->disablescheduledbackups)) { // Defined in config.php + //Execute backup's cron + //Perhaps a long time and memory could help in large sites + @set_time_limit(0); + @raise_memory_limit("192M"); + if (function_exists('apache_child_terminate')) { + // if we are running from Apache, give httpd a hint that + // it can recycle the process after it's done. Apache's + // memory management is truly awful but we can help it. + @apache_child_terminate(); + } + if (file_exists("$CFG->dirroot/backup/backup_scheduled.php") and + file_exists("$CFG->dirroot/backup/backuplib.php") and + file_exists("$CFG->dirroot/backup/lib.php") and + file_exists("$CFG->libdir/blocklib.php")) { + include_once("$CFG->dirroot/backup/backup_scheduled.php"); + include_once("$CFG->dirroot/backup/backuplib.php"); + include_once("$CFG->dirroot/backup/lib.php"); + mtrace("Running backups if required..."); + + if (! schedule_backup_cron()) { + mtrace("ERROR: Something went wrong while performing backup tasks!!!"); + } else { + mtrace("Backup tasks finished."); + } + } + } + +/// 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()); + } + + if (!empty($CFG->enablestats) and empty($CFG->disablestatsprocessing)) { + require_once($CFG->dirroot.'/lib/statslib.php'); + // check we're not before our runtime + $timetocheck = stats_get_base_daily() + $CFG->statsruntimestarthour*60*60 + $CFG->statsruntimestartminute*60; + + if (time() > $timetocheck) { + // process configured number of days as max (defaulting to 31) + $maxdays = empty($CFG->statsruntimedays) ? 31 : abs($CFG->statsruntimedays); + if (stats_cron_daily($maxdays)) { + if (stats_cron_weekly()) { + if (stats_cron_monthly()) { + stats_clean_old(); + } + } + } + @set_time_limit(0); + } else { + mtrace('Next stats run after:'. userdate($timetocheck)); + } + } + + // run gradebook import/export/report cron + if ($gradeimports = get_plugin_list('gradeimport')) { + foreach ($gradeimports as $gradeimport => $plugindir) { + if (file_exists($plugindir.'/lib.php')) { + require_once($plugindir.'/lib.php'); + $cron_function = 'grade_import_'.$gradeimport.'_cron'; + if (function_exists($cron_function)) { + mtrace("Processing gradebook import function $cron_function ...", ''); + $cron_function(); + } + } + } + } + + if ($gradeexports = get_plugin_list('gradeexport')) { + foreach ($gradeexports as $gradeexport => $plugindir) { + if (file_exists($plugindir.'/lib.php')) { + require_once($plugindir.'/lib.php'); + $cron_function = 'grade_export_'.$gradeexport.'_cron'; + if (function_exists($cron_function)) { + mtrace("Processing gradebook export function $cron_function ...", ''); + $cron_function(); + } + } + } + } + + if ($gradereports = get_plugin_list('gradereport')) { + foreach ($gradereports as $gradereport => $plugindir) { + if (file_exists($plugindir.'/lib.php')) { + require_once($plugindir.'/lib.php'); + $cron_function = 'grade_report_'.$gradereport.'_cron'; + if (function_exists($cron_function)) { + mtrace("Processing gradebook report function $cron_function ...", ''); + $cron_function(); + } + } + } + } + + // 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); + } + } + + // 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})'); + } + + //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 + $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.'); + + // run any customized cronjobs, if any + if ($locals = get_plugin_list('local')) { + mtrace('Processing customized cron scripts ...', ''); + foreach ($locals as $local => $localdir) { + if (file_exists("$localdir/cron.php")) { + include("$localdir/cron.php"); + } + } + mtrace('done.'); + } + + + mtrace("Cron script completed correctly"); + + $difftime = microtime_diff($starttime, microtime()); + mtrace("Execution took ".$difftime." seconds"); + +} \ No newline at end of file diff --git a/lib/setup.php b/lib/setup.php index 31b2e8e572f42..5ac876d6360c5 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -99,14 +99,25 @@ } // Detect CLI scripts - CLI scripts are executed from command line, do not have session and we do not want HTML in output -// In your new CLI scripts just add: if (isset($_SERVER['REMOTE_ADDR'])) {die;} before requiring config.php. +// In your new CLI scripts just add "define('CLI_SCRIPT', true);" before requiring config.php. +// Please note that one script can not be accessed from both CLI and web interface. if (!defined('CLI_SCRIPT')) { - // CLI_SCRIPT is defined in 'fake' CLI script /admin/cron.php, do not abuse this elsewhere! - if (isset($_SERVER['REMOTE_ADDR'])) { - define('CLI_SCRIPT', false); - } else { - /** @ignore */ - define('CLI_SCRIPT', true); + define('CLI_SCRIPT', false); +} +if (defined('WEB_CRON_EMULATED_CLI')) { + if (!isset($_SERVER['REMOTE_ADDR'])) { + echo('Web cron can not be executed as CLI script any more, please use admin/cli/cron.php instead'."\n"); + exit(1); + } +} else if (isset($_SERVER['REMOTE_ADDR'])) { + if (CLI_SCRIPT) { + echo('Command line scripts can not be executed from the web interface'); + exit(1); + } +} else { + if (!CLI_SCRIPT) { + echo('Command line scripts must define CLI_SCRIPT before requiring config.php'."\n"); + exit(1); } } @@ -586,7 +597,11 @@ function stripslashes_deep($value) { // init session prevention flag - this is defined on pages that do not want session -if (!defined('NO_MOODLE_COOKIES')) { +if (CLI_SCRIPT) { + // no sessions in CLI scripts possible + define('NO_MOODLE_COOKIES', true); + +} else if (!defined('NO_MOODLE_COOKIES')) { if (empty($CFG->version) or $CFG->version < 2009011900) { // no session before sessions table gets created define('NO_MOODLE_COOKIES', true);