/** * Load handler instances for all of the handlers defined in db/messageinbound_handlers.php for the specified component. * * @param string $componentname - The name of the component to fetch the handlers for. * @return \core\message\inbound\handler[] - List of handlers for this component. */ public static function load_default_handlers_for_component($componentname) { $componentname = \core_component::normalize_componentname($componentname); $dir = \core_component::get_component_directory($componentname); if (!$dir) { return array(); } $file = $dir . '/db/messageinbound_handlers.php'; if (!file_exists($file)) { return array(); } $handlers = null; require_once $file; if (!isset($handlers)) { return array(); } $handlerinstances = array(); foreach ($handlers as $handler) { $record = (object) $handler; $record->component = $componentname; if ($handlerinstance = self::handler_from_record($record)) { $handlerinstances[] = $handlerinstance; } else { throw new \coding_exception("Inbound Message Handler not found for '{$componentname}'."); } } return $handlerinstances; }
/** * Given a component name, will load the list of tasks in the db/tasks.php file for that component. * * @param string $componentname - The name of the component to fetch the tasks for. * @return \core\task\scheduled_task[] - List of scheduled tasks for this component. */ public static function load_default_scheduled_tasks_for_component($componentname) { $dir = \core_component::get_component_directory($componentname); if (!$dir) { return array(); } $file = $dir . '/' . CORE_TASK_TASKS_FILENAME; if (!file_exists($file)) { return array(); } $tasks = null; include $file; if (!isset($tasks)) { return array(); } $scheduledtasks = array(); foreach ($tasks as $task) { $record = (object) $task; $scheduledtask = self::scheduled_task_from_record($record); // Safety check in case the task in the DB does not match a real class (maybe something was uninstalled). if ($scheduledtask) { $scheduledtask->set_component($componentname); $scheduledtasks[] = $scheduledtask; } } return $scheduledtasks; }
/** * Returns detailed function information * * @param string|object $function name of external function or record from external_function * @param int $strictness IGNORE_MISSING means compatible mode, false returned if record not found, debug message if more found; * MUST_EXIST means throw exception if no record or multiple records found * @return stdClass description or false if not found or exception thrown * @since Moodle 2.0 */ function external_function_info($function, $strictness = MUST_EXIST) { global $DB, $CFG; if (!is_object($function)) { if (!($function = $DB->get_record('external_functions', array('name' => $function), '*', $strictness))) { return false; } } //first find and include the ext implementation class $function->classpath = empty($function->classpath) ? core_component::get_component_directory($function->component) . '/externallib.php' : $CFG->dirroot . '/' . $function->classpath; if (!file_exists($function->classpath)) { throw new coding_exception('Can not find file with external function implementation'); } require_once $function->classpath; $function->parameters_method = $function->methodname . '_parameters'; $function->returns_method = $function->methodname . '_returns'; // make sure the implementaion class is ok if (!method_exists($function->classname, $function->methodname)) { throw new coding_exception('Missing implementation method of ' . $function->classname . '::' . $function->methodname); } if (!method_exists($function->classname, $function->parameters_method)) { throw new coding_exception('Missing parameters description'); } if (!method_exists($function->classname, $function->returns_method)) { throw new coding_exception('Missing returned values description'); } // fetch the parameters description $function->parameters_desc = call_user_func(array($function->classname, $function->parameters_method)); if (!$function->parameters_desc instanceof external_function_parameters) { throw new coding_exception('Invalid parameters description'); } // fetch the return values description $function->returns_desc = call_user_func(array($function->classname, $function->returns_method)); // null means void result or result is ignored if (!is_null($function->returns_desc) and !$function->returns_desc instanceof external_description) { throw new coding_exception('Invalid return description'); } //now get the function description //TODO MDL-31115 use localised lang pack descriptions, it would be nice to have // easy to understand descriptions in admin UI, // on the other hand this is still a bit in a flux and we need to find some new naming // conventions for these descriptions in lang packs $function->description = null; $servicesfile = core_component::get_component_directory($function->component) . '/db/services.php'; if (file_exists($servicesfile)) { $functions = null; include $servicesfile; if (isset($functions[$function->name]['description'])) { $function->description = $functions[$function->name]['description']; } if (isset($functions[$function->name]['testclientpath'])) { $function->testclientpath = $functions[$function->name]['testclientpath']; } } return $function; }
/** * Loads the events definitions for the component (from file). If no * events are defined for the component, we simply return an empty array. * * @access protected To be used from eventslib only * * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results' * @return array Array of capabilities or empty array if not exists */ function events_load_def($component) { global $CFG; if ($component === 'unittest') { $defpath = $CFG->dirroot . '/lib/tests/fixtures/events.php'; } else { $defpath = core_component::get_component_directory($component) . '/db/events.php'; } $handlers = array(); if (file_exists($defpath)) { require $defpath; } // make sure the definitions are valid and complete; tell devs what is wrong foreach ($handlers as $eventname => $handler) { if ($eventname === 'reset') { debugging("'reset' can not be used as event name."); unset($handlers['reset']); continue; } if (!is_array($handler)) { debugging("Handler of '{$eventname}' must be specified as array'"); unset($handlers[$eventname]); continue; } if (!isset($handler['handlerfile'])) { debugging("Handler of '{$eventname}' must include 'handlerfile' key'"); unset($handlers[$eventname]); continue; } if (!isset($handler['handlerfunction'])) { debugging("Handler of '{$eventname}' must include 'handlerfunction' key'"); unset($handlers[$eventname]); continue; } if (!isset($handler['schedule'])) { $handler['schedule'] = 'instant'; } if ($handler['schedule'] !== 'instant' and $handler['schedule'] !== 'cron') { debugging("Handler of '{$eventname}' must include valid 'schedule' type (instant or cron)'"); unset($handlers[$eventname]); continue; } if (!isset($handler['internal'])) { $handler['internal'] = 1; } $handlers[$eventname] = $handler; } return $handlers; }
/** * Test requirejs loader */ public function test_requirejs() { global $CFG; // Find a core module. $result = core_requirejs::find_one_amd_module('core', 'templates', false); $expected = ['core/templates' => $CFG->dirroot . '/lib/amd/build/templates.min.js']; $this->assertEquals($expected, $result); $result = core_requirejs::find_one_amd_module('core', 'templates', true); $expected = ['core/templates' => $CFG->dirroot . '/lib/amd/src/templates.js']; $this->assertEquals($expected, $result); // Find a subsystem module (none exist yet). $result = core_requirejs::find_one_amd_module('core_group', 'doesnotexist', false); $expected = []; $this->assertEquals($expected, $result); // Find a plugin module. $result = core_requirejs::find_one_amd_module('mod_assign', 'grading_panel', true); $expected = ['mod_assign/grading_panel' => $CFG->dirroot . '/mod/assign/amd/src/grading_panel.js']; $this->assertEquals($expected, $result); // Find all modules - no debugging. $result = core_requirejs::find_all_amd_modules(true); foreach ($result as $key => $path) { // Lets verify the first part of the key is a valid component name and the second part correctly contains "min" or not. list($component, $template) = explode('/', $key, 2); // Can we resolve it to a valid dir? $dir = core_component::get_component_directory($component); $this->assertNotEmpty($dir); // Only "core" is allowed to have no _ in component names. if (strpos($component, '_') === false) { $this->assertEquals('core', $component); } $this->assertNotContains('.min', $path); } // Find all modules - debugging. $result = core_requirejs::find_all_amd_modules(false); foreach ($result as $key => $path) { // Lets verify the first part of the key is a valid component name and the second part correctly contains "min" or not. list($component, $template) = explode('/', $key, 2); $dir = core_component::get_component_directory($component); $this->assertNotEmpty($dir); // Only "core" is allowed to have no _ in component names. if (strpos($component, '_') === false) { $this->assertEquals('core', $component); } $this->assertContains('.min', $path); } }
/** * Validate data. * * This ensures that: * - Plugins are only used once, * - Group names are unique, * - Lines match: group = plugin[, plugin[, plugin ...]], * - There are some groups and plugins defined, * - The plugins used are installed. * * @param string $data * @return mixed True on success, else error message. */ public function validate($data) { $result = parent::validate($data); if ($result !== true) { return $result; } $lines = explode("\n", $data); $groups = array(); $plugins = array(); foreach ($lines as $line) { if (!trim($line)) { continue; } $matches = array(); if (!preg_match('/^\\s*([a-z0-9]+)\\s*=\\s*([a-z0-9]+(\\s*,\\s*[a-z0-9]+)*)+\\s*$/', $line, $matches)) { $result = get_string('errorcannotparseline', 'editor_atto', $line); break; } $group = $matches[1]; if (isset($groups[$group])) { $result = get_string('errorgroupisusedtwice', 'editor_atto', $group); break; } $groups[$group] = true; $lineplugins = array_map('trim', explode(',', $matches[2])); foreach ($lineplugins as $plugin) { if (isset($plugins[$plugin])) { $result = get_string('errorpluginisusedtwice', 'editor_atto', $plugin); break 2; } else { if (!core_component::get_component_directory('atto_' . $plugin)) { $result = get_string('errorpluginnotfound', 'editor_atto', $plugin); break 2; } } $plugins[$plugin] = true; } } // We did not find any groups or plugins. if (empty($groups) || empty($plugins)) { $result = get_string('errornopluginsorgroupsfound', 'editor_atto'); } return $result; }
/** * Check a single module exists and return the full path to it. * * The expected location for amd modules is: * <componentdir>/amd/src/modulename.js * * @param string $component The component determines the folder the js file should be in. * @param string $jsfilename The filename for the module (with the js extension). * @param boolean $debug If true, returns the paths to the original (unminified) source files. * @return array $files An array of mappings from module names to file paths. * Empty array if the file does not exist. */ public static function find_one_amd_module($component, $jsfilename, $debug = false) { $jsfileroot = core_component::get_component_directory($component); if (!$jsfileroot) { return array(); } $module = str_replace('.js', '', $jsfilename); $srcdir = $jsfileroot . '/amd/build'; $minpart = '.min'; if ($debug) { $srcdir = $jsfileroot . '/amd/src'; $minpart = ''; } $filename = $srcdir . '/' . $module . $minpart . '.js'; if (!file_exists($filename)) { return array(); } $fullmodulename = $component . '/' . $module; return array($fullmodulename => $filename); }
/** * Given a component name, will load the list of tasks in the db/tasks.php file for that component. * * @param string $componentname - The name of the component to fetch the tasks for. * @return \core\task\scheduled_task[] - List of scheduled tasks for this component. */ public static function load_default_scheduled_tasks_for_component($componentname) { $dir = \core_component::get_component_directory($componentname); if (!$dir) { return array(); } $file = $dir . '/' . CORE_TASK_TASKS_FILENAME; if (!file_exists($file)) { return array(); } $tasks = null; require_once $file; if (!isset($tasks)) { return array(); } $scheduledtasks = array(); foreach ($tasks as $task) { $record = (object) $task; $scheduledtask = self::scheduled_task_from_record($record); $scheduledtask->set_component($componentname); $scheduledtasks[] = $scheduledtask; } return $scheduledtasks; }
/** * Adds log entry into upgrade_log table * * @param int $type UPGRADE_LOG_NORMAL, UPGRADE_LOG_NOTICE or UPGRADE_LOG_ERROR * @param string $plugin frankenstyle component name * @param string $info short description text of log entry * @param string $details long problem description * @param string $backtrace string used for errors only * @return void */ function upgrade_log($type, $plugin, $info, $details=null, $backtrace=null) { global $DB, $USER, $CFG; if (empty($plugin)) { $plugin = 'core'; } list($plugintype, $pluginname) = core_component::normalize_component($plugin); $component = is_null($pluginname) ? $plugintype : $plugintype . '_' . $pluginname; $backtrace = format_backtrace($backtrace, true); $currentversion = null; $targetversion = null; //first try to find out current version number if ($plugintype === 'core') { //main $currentversion = $CFG->version; $version = null; include("$CFG->dirroot/version.php"); $targetversion = $version; } else { $pluginversion = get_config($component, 'version'); if (!empty($pluginversion)) { $currentversion = $pluginversion; } $cd = core_component::get_component_directory($component); if (file_exists("$cd/version.php")) { $plugin = new stdClass(); $plugin->version = null; $module = $plugin; include("$cd/version.php"); $targetversion = $plugin->version; } } $log = new stdClass(); $log->type = $type; $log->plugin = $component; $log->version = $currentversion; $log->targetversion = $targetversion; $log->info = $info; $log->details = $details; $log->backtrace = $backtrace; $log->userid = $USER->id; $log->timemodified = time(); try { $DB->insert_record('upgrade_log', $log); } catch (Exception $ignored) { // possible during install or 2.0 upgrade } }
/** * Return user information including profile picture + basic site information * Note: * - no capability checking because we return only known information about logged user * * @param array $serviceshortnames - DEPRECATED PARAMETER - values will be ignored - * it was an original design error, we keep for backward compatibility. * @return array site info * @since Moodle 2.2 */ public static function get_site_info($serviceshortnames = array()) { global $USER, $SITE, $CFG, $DB; $params = self::validate_parameters(self::get_site_info_parameters(), array('serviceshortnames' => $serviceshortnames)); $context = context_user::instance($USER->id); $profileimageurl = moodle_url::make_pluginfile_url($context->id, 'user', 'icon', null, '/', 'f1'); // Site information. $siteinfo = array('sitename' => $SITE->fullname, 'siteurl' => $CFG->wwwroot, 'username' => $USER->username, 'firstname' => $USER->firstname, 'lastname' => $USER->lastname, 'fullname' => fullname($USER), 'lang' => current_language(), 'userid' => $USER->id, 'userpictureurl' => $profileimageurl->out(false)); // Retrieve the service and functions from the web service linked to the token // If you call this function directly from external (not a web service call), // then it will still return site info without information about a service // Note: wsusername/wspassword ws authentication is not supported. $functions = array(); if ($CFG->enablewebservices) { // No need to check token if web service are disabled and not a ws call. $token = optional_param('wstoken', '', PARAM_ALPHANUM); if (!empty($token)) { // No need to run if not a ws call. // Retrieve service shortname. $servicesql = 'SELECT s.* FROM {external_services} s, {external_tokens} t WHERE t.externalserviceid = s.id AND token = ? AND t.userid = ? AND s.enabled = 1'; $service = $DB->get_record_sql($servicesql, array($token, $USER->id)); $siteinfo['downloadfiles'] = $service->downloadfiles; $siteinfo['uploadfiles'] = $service->uploadfiles; if (!empty($service)) { // Return the release and version number for web service users only. $siteinfo['release'] = $CFG->release; $siteinfo['version'] = $CFG->version; // Retrieve the functions. $functionssql = "SELECT f.*\n FROM {external_functions} f, {external_services_functions} sf\n WHERE f.name = sf.functionname AND sf.externalserviceid = ?"; $functions = $DB->get_records_sql($functionssql, array($service->id)); } else { throw new coding_exception('No service found in get_site_info: something is buggy, \\ it should have fail at the ws server authentication layer.'); } } } // Build up the returned values of the list of functions. $componentversions = array(); $availablefunctions = array(); foreach ($functions as $function) { $functioninfo = array(); $functioninfo['name'] = $function->name; if ($function->component == 'moodle' || $function->component == 'core') { $version = $CFG->version; // Moodle version. } else { $versionpath = core_component::get_component_directory($function->component) . '/version.php'; if (is_readable($versionpath)) { // We store the component version once retrieved (so we don't load twice the version.php). if (!isset($componentversions[$function->component])) { $plugin = new stdClass(); include $versionpath; $componentversions[$function->component] = $plugin->version; $version = $plugin->version; } else { $version = $componentversions[$function->component]; } } else { // Function component should always have a version.php, // otherwise the function should have been described with component => 'moodle'. throw new moodle_exception('missingversionfile', 'webservice', '', $function->component); } } $functioninfo['version'] = $version; $availablefunctions[] = $functioninfo; } $siteinfo['functions'] = $availablefunctions; // Mobile CSS theme and alternative login url. $siteinfo['mobilecssurl'] = $CFG->mobilecssurl; // Retrieve some advanced features. Only enable/disable ones (bool). $advancedfeatures = array("usecomments", "usetags", "enablenotes", "messaging", "enableblogs", "enablecompletion", "enablebadges"); foreach ($advancedfeatures as $feature) { if (isset($CFG->{$feature})) { $siteinfo['advancedfeatures'][] = array('name' => $feature, 'value' => (int) $CFG->{$feature}); } } // Special case mnet_dispatcher_mode. $siteinfo['advancedfeatures'][] = array('name' => 'mnet_dispatcher_mode', 'value' => $CFG->mnet_dispatcher_mode == 'strict' ? 1 : 0); // User can manage own files. $siteinfo['usercanmanageownfiles'] = has_capability('moodle/user:manageownfiles', $context); // User quota. 0 means user can ignore the quota. $siteinfo['userquota'] = 0; if (!has_capability('moodle/user:ignoreuserquota', $context)) { $siteinfo['userquota'] = $CFG->userquota; } // User max upload file size. -1 means the user can ignore the upload file size. $siteinfo['usermaxuploadfilesize'] = get_user_max_upload_file_size($context, $CFG->maxbytes); return $siteinfo; }
/** * Called by pluginfile.php to serve files related to the 'question' core * component and for files belonging to qtypes. * * For files that relate to questions in a question_attempt, then we delegate to * a function in the component that owns the attempt (for example in the quiz, * or in core question preview) to get necessary inforation. * * (Note that, at the moment, all question file areas relate to questions in * attempts, so the If at the start of the last paragraph is always true.) * * Does not return, either calls send_file_not_found(); or serves the file. * * @package core_question * @category files * @param stdClass $course course settings object * @param stdClass $context context object * @param string $component the name of the component we are serving files for. * @param string $filearea the name of the file area. * @param array $args the remaining bits of the file path. * @param bool $forcedownload whether the user must be forced to download the file. * @param array $options additional options affecting the file serving */ function question_pluginfile($course, $context, $component, $filearea, $args, $forcedownload, array $options = array()) { global $DB, $CFG; // Special case, sending a question bank export. if ($filearea === 'export') { list($context, $course, $cm) = get_context_info_array($context->id); require_login($course, false, $cm); require_once $CFG->dirroot . '/question/editlib.php'; $contexts = new question_edit_contexts($context); // check export capability $contexts->require_one_edit_tab_cap('export'); $category_id = (int) array_shift($args); $format = array_shift($args); $cattofile = array_shift($args); $contexttofile = array_shift($args); $filename = array_shift($args); // load parent class for import/export require_once $CFG->dirroot . '/question/format.php'; require_once $CFG->dirroot . '/question/editlib.php'; require_once $CFG->dirroot . '/question/format/' . $format . '/format.php'; $classname = 'qformat_' . $format; if (!class_exists($classname)) { send_file_not_found(); } $qformat = new $classname(); if (!($category = $DB->get_record('question_categories', array('id' => $category_id)))) { send_file_not_found(); } $qformat->setCategory($category); $qformat->setContexts($contexts->having_one_edit_tab_cap('export')); $qformat->setCourse($course); if ($cattofile == 'withcategories') { $qformat->setCattofile(true); } else { $qformat->setCattofile(false); } if ($contexttofile == 'withcontexts') { $qformat->setContexttofile(true); } else { $qformat->setContexttofile(false); } if (!$qformat->exportpreprocess()) { send_file_not_found(); print_error('exporterror', 'question', $thispageurl->out()); } // export data to moodle file pool if (!($content = $qformat->exportprocess(true))) { send_file_not_found(); } send_file($content, $filename, 0, 0, true, true, $qformat->mime_type()); } // Normal case, a file belonging to a question. $qubaidorpreview = array_shift($args); // Two sub-cases: 1. A question being previewed outside an attempt/usage. if ($qubaidorpreview === 'preview') { $previewcontextid = (int) array_shift($args); $previewcomponent = array_shift($args); $questionid = (int) array_shift($args); $previewcontext = context_helper::instance_by_id($previewcontextid); $result = component_callback($previewcomponent, 'question_preview_pluginfile', array($previewcontext, $questionid, $context, $component, $filearea, $args, $forcedownload, $options), 'newcallbackmissing'); if ($result === 'newcallbackmissing' && ($filearea = 'questiontext')) { // Fall back to the legacy callback for backwards compatibility. debugging("Component {$previewcomponent} does not define the expected " . "{$previewcomponent}_question_preview_pluginfile callback. Falling back to the deprecated " . "{$previewcomponent}_questiontext_preview_pluginfile callback.", DEBUG_DEVELOPER); component_callback($previewcomponent, 'questiontext_preview_pluginfile', array($previewcontext, $questionid, $args, $forcedownload, $options)); } send_file_not_found(); } // 2. A question being attempted in the normal way. $qubaid = (int) $qubaidorpreview; $slot = (int) array_shift($args); $module = $DB->get_field('question_usages', 'component', array('id' => $qubaid)); if ($module === 'core_question_preview') { require_once $CFG->dirroot . '/question/previewlib.php'; return question_preview_question_pluginfile($course, $context, $component, $filearea, $qubaid, $slot, $args, $forcedownload, $options); } else { $dir = core_component::get_component_directory($module); if (!file_exists("{$dir}/lib.php")) { send_file_not_found(); } include_once "{$dir}/lib.php"; $filefunction = $module . '_question_pluginfile'; if (function_exists($filefunction)) { $filefunction($course, $context, $component, $filearea, $qubaid, $slot, $args, $forcedownload, $options); } // Okay, we're here so lets check for function without 'mod_'. if (strpos($module, 'mod_') === 0) { $filefunctionold = substr($module, 4) . '_question_pluginfile'; if (function_exists($filefunctionold)) { $filefunctionold($course, $context, $component, $filearea, $qubaid, $slot, $args, $forcedownload, $options); } } send_file_not_found(); } }
/** * Assign roles * * This has to be called after enrolments processing. * * @param mixed $data * @return void */ public function process_assignment($data) { global $DB; $data = (object) $data; // Check roleid, userid are one of the mapped ones if (!($newroleid = $this->get_mappingid('role', $data->roleid))) { return; } if (!($newuserid = $this->get_mappingid('user', $data->userid))) { return; } if (!$DB->record_exists('user', array('id' => $newuserid, 'deleted' => 0))) { // Only assign roles to not deleted users return; } if (!($contextid = $this->task->get_contextid())) { return; } if (empty($data->component)) { // assign standard manual roles // TODO: role_assign() needs one userid param to be able to specify our restore userid role_assign($newroleid, $newuserid, $contextid); } else { if (strpos($data->component, 'enrol_') === 0) { // Deal with enrolment roles - ignore the component and just find out the instance via new id, // it is possible that enrolment was restored using different plugin type. if (!isset($this->plugins)) { $this->plugins = enrol_get_plugins(true); } if ($enrolid = $this->get_mappingid('enrol', $data->itemid)) { if ($instance = $DB->get_record('enrol', array('id' => $enrolid))) { if (isset($this->plugins[$instance->enrol])) { $this->plugins[$instance->enrol]->restore_role_assignment($instance, $newroleid, $newuserid, $contextid); } } } } else { $data->roleid = $newroleid; $data->userid = $newuserid; $data->contextid = $contextid; $dir = core_component::get_component_directory($data->component); if ($dir and is_dir($dir)) { if (component_callback($data->component, 'restore_role_assignment', array($this, $data), true)) { return; } } // Bad luck, plugin could not restore the data, let's add normal membership. role_assign($data->roleid, $data->userid, $data->contextid); $message = "Restore of '{$data->component}/{$data->itemid}' role assignments is not supported, using manual role assignments instead."; $this->log($message, backup::LOG_WARNING); } } }
} if ($version === 'moodle') { if (count($bits) <= 3) { // This is an invalid module load attempt. $content .= "\n// Incorrect moodle module inclusion. Not enough component information in {$part}.\n"; continue; } $revision = (int)array_shift($bits); if ($revision === -1) { // Revision -1 says please don't cache the JS $cache = false; } $frankenstyle = array_shift($bits); $filename = array_pop($bits); $modulename = $bits[0]; $dir = core_component::get_component_directory($frankenstyle); // For shifted YUI modules, we need the YUI module name in frankenstyle format. $frankenstylemodulename = join('-', array($version, $frankenstyle, $modulename)); $frankenstylefilename = preg_replace('/' . $modulename . '/', $frankenstylemodulename, $filename); // Submodules are stored in a directory with the full submodule name. // We need to remove the -debug.js, -min.js, and .js from the file name to calculate that directory name. $frankenstyledirectoryname = str_replace(array('-min.js', '-debug.js', '.js', '.css'), '', $frankenstylefilename); // By default, try and use the /yui/build directory. $contentfile = $dir . '/yui/build/' . $frankenstyledirectoryname; if ($mimetype == 'text/css') { // CSS assets are in a slightly different place to the JS. $contentfile = $contentfile . '/assets/skins/sam/' . $frankenstylefilename;
/** * Loads the messages definitions for a component from file * * If no messages are defined for the component, return an empty array. * This is an internal function used within messagelib.php * * @see message_update_providers() * @see message_update_processors() * @param string $component A moodle component like 'moodle', 'mod_forum', 'block_quiz_results' * @return array An array of message providers or empty array if not exists */ function message_get_providers_from_file($component) { $defpath = core_component::get_component_directory($component).'/db/messages.php'; $messageproviders = array(); if (file_exists($defpath)) { require($defpath); } foreach ($messageproviders as $name => $messageprovider) { // Fix up missing values if required if (empty($messageprovider['capability'])) { $messageproviders[$name]['capability'] = NULL; } if (empty($messageprovider['defaults'])) { $messageproviders[$name]['defaults'] = array(); } } return $messageproviders; }
/** * This function delegates file serving to individual plugins * * @param string $relativepath * @param bool $forcedownload * @param null|string $preview the preview mode, defaults to serving the original file * @todo MDL-31088 file serving improments */ function file_pluginfile($relativepath, $forcedownload, $preview = null) { global $DB, $CFG, $USER; // relative path must start with '/' if (!$relativepath) { print_error('invalidargorconf'); } else { if ($relativepath[0] != '/') { print_error('pathdoesnotstartslash'); } } // extract relative path components $args = explode('/', ltrim($relativepath, '/')); if (count($args) < 3) { // always at least context, component and filearea print_error('invalidarguments'); } $contextid = (int) array_shift($args); $component = clean_param(array_shift($args), PARAM_COMPONENT); $filearea = clean_param(array_shift($args), PARAM_AREA); list($context, $course, $cm) = get_context_info_array($contextid); $fs = get_file_storage(); // ======================================================================================================================== if ($component === 'blog') { // Blog file serving if ($context->contextlevel != CONTEXT_SYSTEM) { send_file_not_found(); } if ($filearea !== 'attachment' and $filearea !== 'post') { send_file_not_found(); } if (empty($CFG->enableblogs)) { print_error('siteblogdisable', 'blog'); } $entryid = (int) array_shift($args); if (!($entry = $DB->get_record('post', array('module' => 'blog', 'id' => $entryid)))) { send_file_not_found(); } if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL) { require_login(); if (isguestuser()) { print_error('noguest'); } if ($CFG->bloglevel == BLOG_USER_LEVEL) { if ($USER->id != $entry->userid) { send_file_not_found(); } } } if ($entry->publishstate === 'public') { if ($CFG->forcelogin) { require_login(); } } else { if ($entry->publishstate === 'site') { require_login(); //ok } else { if ($entry->publishstate === 'draft') { require_login(); if ($USER->id != $entry->userid) { send_file_not_found(); } } } } $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, $component, $filearea, $entryid, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } send_stored_file($file, 10 * 60, 0, true, array('preview' => $preview)); // download MUST be forced - security! // ======================================================================================================================== } else { if ($component === 'grade') { if (($filearea === 'outcome' or $filearea === 'scale') and $context->contextlevel == CONTEXT_SYSTEM) { // Global gradebook files if ($CFG->forcelogin) { require_login(); } $fullpath = "/{$context->id}/{$component}/{$filearea}/" . implode('/', $args); if (!($file = $fs->get_file_by_hash(sha1($fullpath))) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { if ($filearea === 'feedback' and $context->contextlevel == CONTEXT_COURSE) { //TODO: nobody implemented this yet in grade edit form!! send_file_not_found(); if ($CFG->forcelogin || $course->id != SITEID) { require_login($course); } $fullpath = "/{$context->id}/{$component}/{$filearea}/" . implode('/', $args); if (!($file = $fs->get_file_by_hash(sha1($fullpath))) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { send_file_not_found(); } } // ======================================================================================================================== } else { if ($component === 'tag') { if ($filearea === 'description' and $context->contextlevel == CONTEXT_SYSTEM) { // All tag descriptions are going to be public but we still need to respect forcelogin if ($CFG->forcelogin) { require_login(); } $fullpath = "/{$context->id}/tag/description/" . implode('/', $args); if (!($file = $fs->get_file_by_hash(sha1($fullpath))) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, true, array('preview' => $preview)); } else { send_file_not_found(); } // ======================================================================================================================== } else { if ($component === 'badges') { require_once $CFG->libdir . '/badgeslib.php'; $badgeid = (int) array_shift($args); $badge = new badge($badgeid); $filename = array_pop($args); if ($filearea === 'badgeimage') { if ($filename !== 'f1' && $filename !== 'f2') { send_file_not_found(); } if (!($file = $fs->get_file($context->id, 'badges', 'badgeimage', $badge->id, '/', $filename . '.png'))) { send_file_not_found(); } \core\session\manager::write_close(); send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { if ($filearea === 'userbadge' and $context->contextlevel == CONTEXT_USER) { if (!($file = $fs->get_file($context->id, 'badges', 'userbadge', $badge->id, '/', $filename . '.png'))) { send_file_not_found(); } \core\session\manager::write_close(); send_stored_file($file, 60 * 60, 0, true, array('preview' => $preview)); } } // ======================================================================================================================== } else { if ($component === 'calendar') { if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_SYSTEM) { // All events here are public the one requirement is that we respect forcelogin if ($CFG->forcelogin) { require_login(); } // Get the event if from the args array $eventid = array_shift($args); // Load the event from the database if (!($event = $DB->get_record('event', array('id' => (int) $eventid, 'eventtype' => 'site')))) { send_file_not_found(); } // Get the file and serve if successful $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_USER) { // Must be logged in, if they are not then they obviously can't be this user require_login(); // Don't want guests here, potentially saves a DB call if (isguestuser()) { send_file_not_found(); } // Get the event if from the args array $eventid = array_shift($args); // Load the event from the database - user id must match if (!($event = $DB->get_record('event', array('id' => (int) $eventid, 'userid' => $USER->id, 'eventtype' => 'user')))) { send_file_not_found(); } // Get the file and serve if successful $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 0, 0, true, array('preview' => $preview)); } else { if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_COURSE) { // Respect forcelogin and require login unless this is the site.... it probably // should NEVER be the site if ($CFG->forcelogin || $course->id != SITEID) { require_login($course); } // Must be able to at least view the course. This does not apply to the front page. if ($course->id != SITEID && !is_enrolled($context) && !is_viewing($context)) { //TODO: hmm, do we really want to block guests here? send_file_not_found(); } // Get the event id $eventid = array_shift($args); // Load the event from the database we need to check whether it is // a) valid course event // b) a group event // Group events use the course context (there is no group context) if (!($event = $DB->get_record('event', array('id' => (int) $eventid, 'courseid' => $course->id)))) { send_file_not_found(); } // If its a group event require either membership of view all groups capability if ($event->eventtype === 'group') { if (!has_capability('moodle/site:accessallgroups', $context) && !groups_is_member($event->groupid, $USER->id)) { send_file_not_found(); } } else { if ($event->eventtype === 'course' || $event->eventtype === 'site') { // Ok. Please note that the event type 'site' still uses a course context. } else { // Some other type. send_file_not_found(); } } // If we get this far we can serve the file $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { send_file_not_found(); } } } // ======================================================================================================================== } else { if ($component === 'user') { if ($filearea === 'icon' and $context->contextlevel == CONTEXT_USER) { if (count($args) == 1) { $themename = theme_config::DEFAULT_THEME; $filename = array_shift($args); } else { $themename = array_shift($args); $filename = array_shift($args); } // fix file name automatically if ($filename !== 'f1' and $filename !== 'f2' and $filename !== 'f3') { $filename = 'f1'; } if ((!empty($CFG->forcelogin) and !isloggedin()) || !empty($CFG->forceloginforprofileimage) && (!isloggedin() || isguestuser())) { // protect images if login required and not logged in; // also if login is required for profile images and is not logged in or guest // do not use require_login() because it is expensive and not suitable here anyway $theme = theme_config::load($themename); redirect($theme->pix_url('u/' . $filename, 'moodle')); // intentionally not cached } if (!($file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename . '.png'))) { if (!($file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename . '.jpg'))) { if ($filename === 'f3') { // f3 512x512px was introduced in 2.3, there might be only the smaller version. if (!($file = $fs->get_file($context->id, 'user', 'icon', 0, '/', 'f1.png'))) { $file = $fs->get_file($context->id, 'user', 'icon', 0, '/', 'f1.jpg'); } } } } if (!$file) { // bad reference - try to prevent future retries as hard as possible! if ($user = $DB->get_record('user', array('id' => $context->instanceid), 'id, picture')) { if ($user->picture > 0) { $DB->set_field('user', 'picture', 0, array('id' => $user->id)); } } // no redirect here because it is not cached $theme = theme_config::load($themename); $imagefile = $theme->resolve_image_location('u/' . $filename, 'moodle', null); send_file($imagefile, basename($imagefile), 60 * 60 * 24 * 14); } $options = array('preview' => $preview); if (empty($CFG->forcelogin) && empty($CFG->forceloginforprofileimage)) { // Profile images should be cache-able by both browsers and proxies according // to $CFG->forcelogin and $CFG->forceloginforprofileimage. $options['cacheability'] = 'public'; } send_stored_file($file, 60 * 60 * 24 * 365, 0, false, $options); // enable long caching, there are many images on each page } else { if ($filearea === 'private' and $context->contextlevel == CONTEXT_USER) { require_login(); if (isguestuser()) { send_file_not_found(); } if ($USER->id !== $context->instanceid) { send_file_not_found(); } $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, $component, $filearea, 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 0, 0, true, array('preview' => $preview)); // must force download - security! } else { if ($filearea === 'profile' and $context->contextlevel == CONTEXT_USER) { if ($CFG->forcelogin) { require_login(); } $userid = $context->instanceid; if ($USER->id == $userid) { // always can access own } else { if (!empty($CFG->forceloginforprofiles)) { require_login(); if (isguestuser()) { send_file_not_found(); } // we allow access to site profile of all course contacts (usually teachers) if (!has_coursecontact_role($userid) && !has_capability('moodle/user:viewdetails', $context)) { send_file_not_found(); } $canview = false; if (has_capability('moodle/user:viewdetails', $context)) { $canview = true; } else { $courses = enrol_get_my_courses(); } while (!$canview && count($courses) > 0) { $course = array_shift($courses); if (has_capability('moodle/user:viewdetails', context_course::instance($course->id))) { $canview = true; } } } } $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, $component, $filearea, 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 0, 0, true, array('preview' => $preview)); // must force download - security! } else { if ($filearea === 'profile' and $context->contextlevel == CONTEXT_COURSE) { $userid = (int) array_shift($args); $usercontext = context_user::instance($userid); if ($CFG->forcelogin) { require_login(); } if (!empty($CFG->forceloginforprofiles)) { require_login(); if (isguestuser()) { print_error('noguest'); } //TODO: review this logic of user profile access prevention if (!has_coursecontact_role($userid) and !has_capability('moodle/user:viewdetails', $usercontext)) { print_error('usernotavailable'); } if (!has_capability('moodle/user:viewdetails', $context) && !has_capability('moodle/user:viewdetails', $usercontext)) { print_error('cannotviewprofile'); } if (!is_enrolled($context, $userid)) { print_error('notenrolledprofile'); } if (groups_get_course_groupmode($course) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { print_error('groupnotamember'); } } $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($usercontext->id, 'user', 'profile', 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 0, 0, true, array('preview' => $preview)); // must force download - security! } else { if ($filearea === 'backup' and $context->contextlevel == CONTEXT_USER) { require_login(); if (isguestuser()) { send_file_not_found(); } $userid = $context->instanceid; if ($USER->id != $userid) { send_file_not_found(); } $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'user', 'backup', 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 0, 0, true, array('preview' => $preview)); // must force download - security! } else { send_file_not_found(); } } } } } // ======================================================================================================================== } else { if ($component === 'coursecat') { if ($context->contextlevel != CONTEXT_COURSECAT) { send_file_not_found(); } if ($filearea === 'description') { if ($CFG->forcelogin) { // no login necessary - unless login forced everywhere require_login(); } $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'coursecat', 'description', 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { send_file_not_found(); } // ======================================================================================================================== } else { if ($component === 'course') { if ($context->contextlevel != CONTEXT_COURSE) { send_file_not_found(); } if ($filearea === 'summary' || $filearea === 'overviewfiles') { if ($CFG->forcelogin) { require_login(); } $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'course', $filearea, 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { if ($filearea === 'section') { if ($CFG->forcelogin) { require_login($course); } else { if ($course->id != SITEID) { require_login($course); } } $sectionid = (int) array_shift($args); if (!($section = $DB->get_record('course_sections', array('id' => $sectionid, 'course' => $course->id)))) { send_file_not_found(); } $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'course', 'section', $sectionid, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { send_file_not_found(); } } } else { if ($component === 'cohort') { $cohortid = (int) array_shift($args); $cohort = $DB->get_record('cohort', array('id' => $cohortid), '*', MUST_EXIST); $cohortcontext = context::instance_by_id($cohort->contextid); // The context in the file URL must be either cohort context or context of the course underneath the cohort's context. if ($context->id != $cohort->contextid && ($context->contextlevel != CONTEXT_COURSE || !in_array($cohort->contextid, $context->get_parent_context_ids()))) { send_file_not_found(); } // User is able to access cohort if they have view cap on cohort level or // the cohort is visible and they have view cap on course level. $canview = has_capability('moodle/cohort:view', $cohortcontext) || $cohort->visible && has_capability('moodle/cohort:view', $context); if ($filearea === 'description' && $canview) { $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (($file = $fs->get_file($cohortcontext->id, 'cohort', 'description', $cohort->id, $filepath, $filename)) && !$file->is_directory()) { \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } } send_file_not_found(); } else { if ($component === 'group') { if ($context->contextlevel != CONTEXT_COURSE) { send_file_not_found(); } require_course_login($course, true, null, false); $groupid = (int) array_shift($args); $group = $DB->get_record('groups', array('id' => $groupid, 'courseid' => $course->id), '*', MUST_EXIST); if ($course->groupmodeforce and $course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context) and !groups_is_member($group->id, $USER->id)) { // do not allow access to separate group info if not member or teacher send_file_not_found(); } if ($filearea === 'description') { require_login($course); $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'group', 'description', $group->id, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { if ($filearea === 'icon') { $filename = array_pop($args); if ($filename !== 'f1' and $filename !== 'f2') { send_file_not_found(); } if (!($file = $fs->get_file($context->id, 'group', 'icon', $group->id, '/', $filename . '.png'))) { if (!($file = $fs->get_file($context->id, 'group', 'icon', $group->id, '/', $filename . '.jpg'))) { send_file_not_found(); } } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, false, array('preview' => $preview)); } else { send_file_not_found(); } } } else { if ($component === 'grouping') { if ($context->contextlevel != CONTEXT_COURSE) { send_file_not_found(); } require_login($course); $groupingid = (int) array_shift($args); // note: everybody has access to grouping desc images for now if ($filearea === 'description') { $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'grouping', 'description', $groupingid, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { send_file_not_found(); } // ======================================================================================================================== } else { if ($component === 'backup') { if ($filearea === 'course' and $context->contextlevel == CONTEXT_COURSE) { require_login($course); require_capability('moodle/backup:downloadfile', $context); $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'backup', 'course', 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 0, 0, $forcedownload, array('preview' => $preview)); } else { if ($filearea === 'section' and $context->contextlevel == CONTEXT_COURSE) { require_login($course); require_capability('moodle/backup:downloadfile', $context); $sectionid = (int) array_shift($args); $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'backup', 'section', $sectionid, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { if ($filearea === 'activity' and $context->contextlevel == CONTEXT_MODULE) { require_login($course, false, $cm); require_capability('moodle/backup:downloadfile', $context); $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'backup', 'activity', 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { if ($filearea === 'automated' and $context->contextlevel == CONTEXT_COURSE) { // Backup files that were generated by the automated backup systems. require_login($course); require_capability('moodle/site:config', $context); $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'backup', 'automated', 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 0, 0, $forcedownload, array('preview' => $preview)); } else { send_file_not_found(); } } } } // ======================================================================================================================== } else { if ($component === 'question') { require_once $CFG->libdir . '/questionlib.php'; question_pluginfile($course, $context, 'question', $filearea, $args, $forcedownload); send_file_not_found(); // ======================================================================================================================== } else { if ($component === 'grading') { if ($filearea === 'description') { // files embedded into the form definition description if ($context->contextlevel == CONTEXT_SYSTEM) { require_login(); } else { if ($context->contextlevel >= CONTEXT_COURSE) { require_login($course, false, $cm); } else { send_file_not_found(); } } $formid = (int) array_shift($args); $sql = "SELECT ga.id\n FROM {grading_areas} ga\n JOIN {grading_definitions} gd ON (gd.areaid = ga.id)\n WHERE gd.id = ? AND ga.contextid = ?"; $areaid = $DB->get_field_sql($sql, array($formid, $context->id), IGNORE_MISSING); if (!$areaid) { send_file_not_found(); } $fullpath = "/{$context->id}/{$component}/{$filearea}/{$formid}/" . implode('/', $args); if (!($file = $fs->get_file_by_hash(sha1($fullpath))) or $file->is_directory()) { send_file_not_found(); } \core\session\manager::write_close(); // Unlock session during file serving. send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } // ======================================================================================================================== } else { if (strpos($component, 'mod_') === 0) { $modname = substr($component, 4); if (!file_exists("{$CFG->dirroot}/mod/{$modname}/lib.php")) { send_file_not_found(); } require_once "{$CFG->dirroot}/mod/{$modname}/lib.php"; if ($context->contextlevel == CONTEXT_MODULE) { if ($cm->modname !== $modname) { // somebody tries to gain illegal access, cm type must match the component! send_file_not_found(); } } if ($filearea === 'intro') { if (!plugin_supports('mod', $modname, FEATURE_MOD_INTRO, true)) { send_file_not_found(); } require_course_login($course, true, $cm); // all users may access it $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'mod_' . $modname, 'intro', 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } // finally send the file send_stored_file($file, null, 0, false, array('preview' => $preview)); } $filefunction = $component . '_pluginfile'; $filefunctionold = $modname . '_pluginfile'; if (function_exists($filefunction)) { // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found" $filefunction($course, $cm, $context, $filearea, $args, $forcedownload, array('preview' => $preview)); } else { if (function_exists($filefunctionold)) { // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found" $filefunctionold($course, $cm, $context, $filearea, $args, $forcedownload, array('preview' => $preview)); } } send_file_not_found(); // ======================================================================================================================== } else { if (strpos($component, 'block_') === 0) { $blockname = substr($component, 6); // note: no more class methods in blocks please, that is .... if (!file_exists("{$CFG->dirroot}/blocks/{$blockname}/lib.php")) { send_file_not_found(); } require_once "{$CFG->dirroot}/blocks/{$blockname}/lib.php"; if ($context->contextlevel == CONTEXT_BLOCK) { $birecord = $DB->get_record('block_instances', array('id' => $context->instanceid), '*', MUST_EXIST); if ($birecord->blockname !== $blockname) { // somebody tries to gain illegal access, cm type must match the component! send_file_not_found(); } if ($context->get_course_context(false)) { // If block is in course context, then check if user has capability to access course. require_course_login($course); } else { if ($CFG->forcelogin) { // If user is logged out, bp record will not be visible, even if the user would have access if logged in. require_login(); } } $bprecord = $DB->get_record('block_positions', array('contextid' => $context->id, 'blockinstanceid' => $context->instanceid)); // User can't access file, if block is hidden or doesn't have block:view capability if ($bprecord && !$bprecord->visible || !has_capability('moodle/block:view', $context)) { send_file_not_found(); } } else { $birecord = null; } $filefunction = $component . '_pluginfile'; if (function_exists($filefunction)) { // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found" $filefunction($course, $birecord, $context, $filearea, $args, $forcedownload, array('preview' => $preview)); } send_file_not_found(); // ======================================================================================================================== } else { if (strpos($component, '_') === false) { // all core subsystems have to be specified above, no more guessing here! send_file_not_found(); } else { // try to serve general plugin file in arbitrary context $dir = core_component::get_component_directory($component); if (!file_exists("{$dir}/lib.php")) { send_file_not_found(); } include_once "{$dir}/lib.php"; $filefunction = $component . '_pluginfile'; if (function_exists($filefunction)) { // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found" $filefunction($course, $cm, $context, $filearea, $args, $forcedownload, array('preview' => $preview)); } send_file_not_found(); } } } } } } } } } } } } } } } } } }
function report_comments_getcoursecomments($courseid, $sort = 'date') { global $CFG, $DB; $formatoptions = array('overflowdiv' => true); $strftimeformat = get_string('strftimerecentfull', 'langconfig'); $context = context_course::instance($courseid); $comments = $DB->get_records('comments', array('contextid' => $context->id)); foreach ($comments as $comment) { $user = $DB->get_record('user', array('id' => $comment->userid), 'firstname, lastname'); $url = new moodle_url('/report/comments/index.php', array('id' => $comment->userid, 'course' => $courseid)); $comment->fullname = html_writer::link($url, $user->firstname . ' ' . $user->lastname); $comment->time = userdate($comment->timecreated, $strftimeformat); $url = new moodle_url('/course/view.php', array('id' => $courseid)); $comment->content = html_writer::link($url, format_text($comment->content, $comment->format, $formatoptions)); } $rawmods = get_course_mods($courseid); foreach ($rawmods as $mod) { if ($context = $DB->get_record('context', array('instanceid' => $mod->id, 'contextlevel' => CONTEXT_MODULE))) { if ($modcomments = $DB->get_records('comments', array('contextid' => $context->id))) { foreach ($modcomments as $comment) { $user = $DB->get_record('user', array('id' => $comment->userid), 'firstname, lastname'); $url = new moodle_url('/report/comments/index.php', array('course' => $courseid, 'id' => $comment->userid)); $comment->fullname = html_writer::link($url, $user->firstname . ' ' . $user->lastname); $comment->time = userdate($comment->timecreated, $strftimeformat); $base = core_component::get_component_directory('mod_' . $mod->modname); if (file_exists("{$base}/view.php")) { $base = substr($base, strlen($CFG->dirroot)); $url = new moodle_url("{$base}/view.php", array('id' => $mod->id)); $comment->content = html_writer::link($url, format_text($comment->content, $comment->format, $formatoptions)); } else { $comment->content = format_text($comment->content, $comment->format, $formatoptions); } $comments[] = $comment; } } } } switch ($sort) { case 'date': usort($comments, "cmpdate"); break; case 'content': usort($comments, "cmpcontent"); break; case 'author': usort($comments, "cmpid"); break; } return $comments; }
/** * Return generator for given plugin or component. * @param string $component the component name, e.g. 'mod_forum' or 'core_question'. * @return component_generator_base or rather an instance of the appropriate subclass. */ public function get_plugin_generator($component) { list($type, $plugin) = core_component::normalize_component($component); $cleancomponent = $type . '_' . $plugin; if ($cleancomponent != $component) { debugging("Please specify the component you want a generator for as " . "{$cleancomponent}, not {$component}.", DEBUG_DEVELOPER); $component = $cleancomponent; } if (isset($this->generators[$component])) { return $this->generators[$component]; } $dir = core_component::get_component_directory($component); $lib = $dir . '/tests/generator/lib.php'; if (!$dir || !is_readable($lib)) { throw new coding_exception("Component {$component} does not support " . "generators yet. Missing tests/generator/lib.php."); } include_once $lib; $classname = $component . '_generator'; if (!class_exists($classname)) { throw new coding_exception("Component {$component} does not support " . "data generators yet. Class {$classname} not found."); } $this->generators[$component] = new $classname($this); return $this->generators[$component]; }
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once __DIR__ . '/../../config.php'; require_once $CFG->libdir . '/adminlib.php'; // Required parameters. $eventname = required_param('eventname', PARAM_RAW); admin_externalpage_setup('reporteventlists'); // Retrieve all events in a list. $completelist = report_eventlist_list_generator::get_all_events_list(false); // Check that $eventname is a valid event. if (!array_key_exists($eventname, $completelist)) { print_error('errorinvalidevent', 'report_eventlist'); } // Break up the full event name to usable parts. $component = explode('\\', $eventname); $directory = core_component::get_component_directory($component[1]); // File and directory information. $directory = $directory . '/classes/event'; // Verify that the directory is valid. if (!is_dir($directory)) { print_error('errorinvaliddirectory', 'report_eventlist'); } $filename = end($component); $eventfiles = $directory . '/' . $filename . '.php'; $title = $eventname::get_name_with_info(); // Define event information. $eventinformation = array('title' => $title); $eventcontents = file_get_contents($eventfiles); $eventinformation['filecontents'] = $eventcontents; $ref = new \ReflectionClass($eventname); $eventinformation['explanation'] = $eventname::get_explanation($eventname);
public function test_get_component_directory() { $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $plugintype => $fulldir) { $plugins = core_component::get_plugin_list($plugintype); foreach ($plugins as $pluginname => $plugindir) { $this->assertSame($plugindir, core_component::get_component_directory($plugintype . '_' . $pluginname)); } } $subsystems = core_component::get_core_subsystems(); foreach ($subsystems as $subsystem => $fulldir) { $this->assertSame($fulldir, core_component::get_component_directory('core_' . $subsystem)); } }
\core\session\manager::set_user($user); //for login and capability checks try { $autologinguest = true; $setwantsurltome = true; $preventredirect = true; require_login($course, $autologinguest, $cm, $setwantsurltome, $preventredirect); } catch (Exception $e) { if (isguestuser()) { rss_error('rsserrorguest'); } else { rss_error('rsserrorauth'); } } // Work out which component in Moodle we want (from the frankenstyle name) $componentdir = core_component::get_component_directory($componentname); list($type, $plugin) = core_component::normalize_component($componentname); // Call the component to check/update the feed and tell us the path to the cached file $pathname = null; if (file_exists($componentdir)) { require_once "{$componentdir}/rsslib.php"; $functionname = $plugin . '_rss_get_feed'; if (function_exists($functionname)) { // $pathname will be null if there was a problem (eg user doesn't have the necessary capabilities) // NOTE:the component providing the feed must do its own capability checks and security try { $pathname = $functionname($context, $args); } catch (Exception $e) { rss_error('rsserror'); } }
/** * Returns the human-readable, translated version of the capability. * Basically a big switch statement. * * @param string $capabilityname e.g. mod/choice:readresponses * @return string */ function get_capability_string($capabilityname) { // Typical capability name is 'plugintype/pluginname:capabilityname' list($type, $name, $capname) = preg_split('|[/:]|', $capabilityname); if ($type === 'moodle') { $component = 'core_role'; } else if ($type === 'quizreport') { //ugly hack!! $component = 'quiz_'.$name; } else { $component = $type.'_'.$name; } $stringname = $name.':'.$capname; if ($component === 'core_role' or get_string_manager()->string_exists($stringname, $component)) { return get_string($stringname, $component); } $dir = core_component::get_component_directory($component); if (!file_exists($dir)) { // plugin broken or does not exist, do not bother with printing of debug message return $capabilityname.' ???'; } // something is wrong in plugin, better print debug return get_string($stringname, $component); }
/** * Adds a specified user to a group * * @param mixed $grouporid The group id or group object * @param mixed $userorid The user id or user object * @param string $component Optional component name e.g. 'enrol_imsenterprise' * @param int $itemid Optional itemid associated with component * @return bool True if user added successfully or the user is already a * member of the group, false otherwise. */ function groups_add_member($grouporid, $userorid, $component = null, $itemid = 0) { global $DB; if (is_object($userorid)) { $userid = $userorid->id; $user = $userorid; if (!isset($user->deleted)) { $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST); } } else { $userid = $userorid; $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST); } if ($user->deleted) { return false; } if (is_object($grouporid)) { $groupid = $grouporid->id; $group = $grouporid; } else { $groupid = $grouporid; $group = $DB->get_record('groups', array('id' => $groupid), '*', MUST_EXIST); } // Check if the user a participant of the group course. $context = context_course::instance($group->courseid); if (!is_enrolled($context, $userid)) { return false; } if (groups_is_member($groupid, $userid)) { return true; } $member = new stdClass(); $member->groupid = $groupid; $member->userid = $userid; $member->timeadded = time(); $member->component = ''; $member->itemid = 0; // Check the component exists if specified if (!empty($component)) { $dir = core_component::get_component_directory($component); if ($dir && is_dir($dir)) { // Component exists and can be used $member->component = $component; $member->itemid = $itemid; } else { throw new coding_exception('Invalid call to groups_add_member(). An invalid component was specified'); } } if ($itemid !== 0 && empty($member->component)) { // An itemid can only be specified if a valid component was found throw new coding_exception('Invalid call to groups_add_member(). A component must be specified if an itemid is given'); } $DB->insert_record('groups_members', $member); // Update group info, and group object. $DB->set_field('groups', 'timemodified', $member->timeadded, array('id' => $groupid)); $group->timemodified = $member->timeadded; // Trigger group event. $params = array('context' => $context, 'objectid' => $groupid, 'relateduserid' => $userid, 'other' => array('component' => $member->component, 'itemid' => $member->itemid)); $event = \core\event\group_member_added::create($params); $event->add_record_snapshot('groups', $group); $event->trigger(); return true; }
/** * Determine if a component callback exists and return the function name to call. Note that this * function will include the required library files so that the functioname returned can be * called directly. * * @param string $component frankenstyle component name, e.g. 'mod_quiz' * @param string $function the rest of the function name, e.g. 'cron' will end up calling 'mod_quiz_cron' * @return mixed Complete function name to call if the callback exists or false if it doesn't. * @throws coding_exception if invalid component specfied */ function component_callback_exists($component, $function) { global $CFG; // This is needed for the inclusions. $cleancomponent = clean_param($component, PARAM_COMPONENT); if (empty($cleancomponent)) { throw new coding_exception('Invalid component used in plugin/component_callback():' . $component); } $component = $cleancomponent; list($type, $name) = core_component::normalize_component($component); $component = $type . '_' . $name; $oldfunction = $name . '_' . $function; $function = $component . '_' . $function; $dir = core_component::get_component_directory($component); if (empty($dir)) { throw new coding_exception('Invalid component used in plugin/component_callback():' . $component); } // Load library and look for function. if (file_exists($dir . '/lib.php')) { require_once $dir . '/lib.php'; } if (!function_exists($function) and function_exists($oldfunction)) { if ($type !== 'mod' and $type !== 'core') { debugging("Please use new function name {$function} instead of legacy {$oldfunction}", DEBUG_DEVELOPER); } $function = $oldfunction; } if (function_exists($function)) { return $function; } return false; }
/** * For a given module name, return the possible class names * that defines the renderer interface for that module. * * Newer auto-loaded class names are returned as well as the old style _renderable classnames. * * Also, if it exists, include the renderer.php file for that module, so * the class definition of the default renderer has been loaded. * * @param string $component name such as 'core', 'mod_forum' or 'qtype_multichoice'. * @param string $subtype optional subtype such as 'news' resulting to: * '\mod_forum\output\news_renderer' * or '\mod_forum\output\news\renderer' * or non-autoloaded 'mod_forum_news' * @return array[] Each element of the array is an array with keys: * classname - The class name to search * autoloaded - Does this classname assume autoloading? * validwithprefix - Is this class name valid when a prefix is added to it? * validwithoutprefix - Is this class name valid when no prefix is added to it? * @throws coding_exception */ protected function standard_renderer_classnames($component, $subtype = null) { global $CFG; // Needed in included files. $classnames = array(); // Standardize component name ala frankenstyle. list($plugin, $type) = core_component::normalize_component($component); if ($type === null) { $component = $plugin; } else { $component = $plugin . '_' . $type; } if ($component !== 'core') { // Renderers are stored in renderer.php files. if (!($compdirectory = core_component::get_component_directory($component))) { throw new coding_exception('Invalid component specified in renderer request', $component); } $rendererfile = $compdirectory . '/renderer.php'; if (file_exists($rendererfile)) { include_once $rendererfile; } } else { if (!empty($subtype)) { $coresubsystems = core_component::get_core_subsystems(); if (!array_key_exists($subtype, $coresubsystems)) { // There may be nulls. throw new coding_exception('Invalid core subtype "' . $subtype . '" in renderer request', $subtype); } if ($coresubsystems[$subtype]) { $rendererfile = $coresubsystems[$subtype] . '/renderer.php'; if (file_exists($rendererfile)) { include_once $rendererfile; } } } } if (empty($subtype)) { // Theme specific auto-loaded name (only valid when prefixed with the theme name). $classnames[] = array('validwithprefix' => true, 'validwithoutprefix' => false, 'autoloaded' => true, 'classname' => '\\output\\' . $component . '_renderer'); // Standard autoloaded plugin name (not valid with a prefix). $classnames[] = array('validwithprefix' => false, 'validwithoutprefix' => true, 'autoloaded' => true, 'classname' => '\\' . $component . '\\output\\renderer'); // Legacy class name - (valid with or without a prefix). $classnames[] = array('validwithprefix' => true, 'validwithoutprefix' => true, 'autoloaded' => false, 'classname' => $component . '_renderer'); } else { // Theme specific auto-loaded name (only valid when prefixed with the theme name). $classnames[] = array('validwithprefix' => true, 'validwithoutprefix' => false, 'autoloaded' => true, 'classname' => '\\output\\' . $component . '\\' . $subtype . '_renderer'); // Version of the above with subtype being a namespace level on it's own. $classnames[] = array('validwithprefix' => true, 'validwithoutprefix' => false, 'autoloaded' => true, 'classname' => '\\output\\' . $component . '\\' . $subtype . '\\renderer'); // Standard autoloaded plugin name (not valid with a prefix). $classnames[] = array('validwithprefix' => false, 'validwithoutprefix' => true, 'autoloaded' => true, 'classname' => '\\' . $component . '\\output\\' . $subtype . '_renderer'); // Version of the above with subtype being a namespace level on it's own. $classnames[] = array('validwithprefix' => false, 'validwithoutprefix' => true, 'autoloaded' => true, 'classname' => '\\' . $component . '\\output\\' . $subtype . '\\renderer'); // Legacy class name - (valid with or without a prefix). $classnames[] = array('validwithprefix' => true, 'validwithoutprefix' => true, 'autoloaded' => false, 'classname' => $component . '_' . $subtype . '_renderer'); } return $classnames; }
/** * Find the plugin info class for given type. * * @param string $type * @return string name of pluginfo class for give plugin type */ public static function resolve_plugininfo_class($type) { $plugintypes = core_component::get_plugin_types(); if (!isset($plugintypes[$type])) { return '\\core\\plugininfo\\orphaned'; } $parent = core_component::get_subtype_parent($type); if ($parent) { $class = '\\' . $parent . '\\plugininfo\\' . $type; if (class_exists($class)) { $plugintypeclass = $class; } else { if ($dir = core_component::get_component_directory($parent)) { // BC only - use namespace instead! if (file_exists("{$dir}/adminlib.php")) { global $CFG; include_once "{$dir}/adminlib.php"; } if (class_exists('plugininfo_' . $type)) { $plugintypeclass = 'plugininfo_' . $type; debugging('Class "' . $plugintypeclass . '" is deprecated, migrate to "' . $class . '"', DEBUG_DEVELOPER); } else { debugging('Subplugin type "' . $type . '" should define class "' . $class . '"', DEBUG_DEVELOPER); $plugintypeclass = '\\core\\plugininfo\\general'; } } else { $plugintypeclass = '\\core\\plugininfo\\general'; } } } else { $class = '\\core\\plugininfo\\' . $type; if (class_exists($class)) { $plugintypeclass = $class; } else { debugging('All standard types including "' . $type . '" should have plugininfo class!', DEBUG_DEVELOPER); $plugintypeclass = '\\core\\plugininfo\\general'; } } if (!in_array('core\\plugininfo\\base', class_parents($plugintypeclass))) { throw new coding_exception('Class ' . $plugintypeclass . ' must extend \\core\\plugininfo\\base'); } return $plugintypeclass; }
/** * Determine the module metadata for all moodle YUI modules. * * This works through all modules capable of serving YUI modules, and attempts to get * metadata for each of those modules. * * @return Array of module metadata */ private function get_moodle_metadata() { $moodlemodules = array(); // Core isn't a plugin type or subsystem - handle it seperately. if ($module = $this->get_moodle_path_metadata(core_component::get_component_directory('core'))) { $moodlemodules = array_merge($moodlemodules, $module); } // Handle other core subsystems. $subsystems = core_component::get_core_subsystems(); foreach ($subsystems as $subsystem => $path) { if (is_null($path)) { continue; } if ($module = $this->get_moodle_path_metadata($path)) { $moodlemodules = array_merge($moodlemodules, $module); } } // And finally the plugins. $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $plugintype => $pathroot) { $pluginlist = core_component::get_plugin_list($plugintype); foreach ($pluginlist as $plugin => $path) { if ($module = $this->get_moodle_path_metadata($path)) { $moodlemodules = array_merge($moodlemodules, $module); } } } return $moodlemodules; }
/** * Add subplugin structure for a given plugin to any element in the structure restore tree * * This method allows the injection of subplugins (of a specific plugin) parsing and proccessing * to any element in the restore structure. * * NOTE: Initially subplugins were only available for activities (mod), so only the * {@link restore_activity_structure_step} class had support for them, always * looking for /mod/modulenanme subplugins. This new method is a generalization of the * existing one for activities, supporting all subplugins injecting information everywhere. * * @param string $subplugintype type of subplugin as defined in plugin's db/subplugins.php. * @param restore_path_element $element element in the structure restore tree that * we are going to add subplugin information to. * @param string $plugintype type of the plugin. * @param string $pluginname name of the plugin. * @return void */ protected function add_subplugin_structure($subplugintype, $element, $plugintype = null, $pluginname = null) { global $CFG; // This global declaration is required, because where we do require_once($backupfile); // That file may in turn try to do require_once($CFG->dirroot ...). // That worked in the past, we should keep it working. // Verify if this is a BC call for an activity restore. See NOTE above for this special case. if ($plugintype === null and $pluginname === null) { $plugintype = 'mod'; $pluginname = $this->task->get_modulename(); // TODO: Once all the calls have been changed to add both not null plugintype and pluginname, add a debugging here. } // Check the requested plugintype is a valid one. if (!array_key_exists($plugintype, core_component::get_plugin_types())) { throw new restore_step_exception('incorrect_plugin_type', $plugintype); } // Check the requested pluginname, for the specified plugintype, is a valid one. if (!array_key_exists($pluginname, core_component::get_plugin_list($plugintype))) { throw new restore_step_exception('incorrect_plugin_name', array($plugintype, $pluginname)); } // Check the requested subplugintype is a valid one. $subpluginsfile = core_component::get_component_directory($plugintype . '_' . $pluginname) . '/db/subplugins.php'; if (!file_exists($subpluginsfile)) { throw new restore_step_exception('plugin_missing_subplugins_php_file', array($plugintype, $pluginname)); } include $subpluginsfile; if (!array_key_exists($subplugintype, $subplugins)) { throw new restore_step_exception('incorrect_subplugin_type', $subplugintype); } // Every subplugin optionally can have a common/parent subplugin // class for shared stuff. $parentclass = 'restore_' . $plugintype . '_' . $pluginname . '_' . $subplugintype . '_subplugin'; $parentfile = core_component::get_component_directory($plugintype . '_' . $pluginname) . '/backup/moodle2/' . $parentclass . '.class.php'; if (file_exists($parentfile)) { require_once $parentfile; } // Get all the restore path elements, looking across all the subplugin dirs. $subpluginsdirs = core_component::get_plugin_list($subplugintype); foreach ($subpluginsdirs as $name => $subpluginsdir) { $classname = 'restore_' . $subplugintype . '_' . $name . '_subplugin'; $restorefile = $subpluginsdir . '/backup/moodle2/' . $classname . '.class.php'; if (file_exists($restorefile)) { require_once $restorefile; $restoresubplugin = new $classname($subplugintype, $name, $this); // Add subplugin paths to the step. $this->prepare_pathelements($restoresubplugin->define_subplugin_structure($element)); } } }
/** * Return exact absolute path to a plugin directory. * * @deprecated since 2.6, use core_component::normalize_component() * * @param string $component name such as 'moodle', 'mod_forum' * @return string full path to component directory; NULL if not found */ function get_component_directory($component) { // NOTE: do not add any other debugging here, keep forever. return core_component::get_component_directory($component); }
/** * 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 */ function cron_execute_plugin_type($plugintype, $description = null) { global $DB; // Get list from plugin => function for all plugins $plugins = get_plugin_list_with_function($plugintype, 'cron'); // Modify list for backward compatibility (different files/names) $plugins = cron_bc_hack_plugin_functions($plugintype, $plugins); // Return if no plugins with cron function to process if (!$plugins) { return; } if ($description) { mtrace('Starting ' . $description); } foreach ($plugins as $component => $cronfunction) { $dir = core_component::get_component_directory($component); // Get cron period if specified in version.php, otherwise assume every cron $cronperiod = 0; if (file_exists("{$dir}/version.php")) { $plugin = new stdClass(); include "{$dir}/version.php"; if (isset($plugin->cron)) { $cronperiod = $plugin->cron; } } // Using last cron and cron period, don't run if it already ran recently $lastcron = get_config($component, 'lastcron'); if ($cronperiod && $lastcron) { if ($lastcron + $cronperiod > time()) { // do not execute cron yet continue; } } mtrace('Processing cron function for ' . $component . '...'); cron_trace_time_and_memory(); $pre_dbqueries = $DB->perf_get_queries(); $pre_time = microtime(true); $cronfunction(); mtrace("done. (" . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries, " . round(microtime(true) - $pre_time, 2) . " seconds)"); set_config('lastcron', time(), $component); @set_time_limit(0); } if ($description) { mtrace('Finished ' . $description); } }
/** * Use this editor for given element. * * @param string $elementid * @param array $options * @param null $fpoptions */ public function use_editor($elementid, array $options = null, $fpoptions = null) { global $PAGE; $configstr = get_config('editor_atto', 'toolbar'); $grouplines = explode("\n", $configstr); $groups = array(); foreach ($grouplines as $groupline) { $line = explode('=', $groupline); if (count($line) > 1) { $group = trim(array_shift($line)); $plugins = array_map('trim', explode(',', array_shift($line))); $groups[$group] = $plugins; } } $modules = array('moodle-editor_atto-editor'); $options['context'] = empty($options['context']) ? context_system::instance() : $options['context']; $jsplugins = array(); foreach ($groups as $group => $plugins) { $groupplugins = array(); foreach ($plugins as $plugin) { // Do not die on missing plugin. if (!core_component::get_component_directory('atto_' . $plugin)) { continue; } $jsplugin = array(); $jsplugin['name'] = $plugin; $jsplugin['params'] = array(); $modules[] = 'moodle-atto_' . $plugin . '-button'; component_callback('atto_' . $plugin, 'strings_for_js'); $extra = component_callback('atto_' . $plugin, 'params_for_js', array($elementid, $options, $fpoptions)); if ($extra) { $jsplugin = array_merge($jsplugin, $extra); } // We always need the plugin name. $PAGE->requires->string_for_js('pluginname', 'atto_' . $plugin); $groupplugins[] = $jsplugin; } $jsplugins[] = array('group' => $group, 'plugins' => $groupplugins); } $PAGE->requires->strings_for_js(array('editor_command_keycode', 'editor_control_keycode', 'plugin_title_shortcut', 'textrecovered', 'autosavefailed', 'autosavesucceeded', 'errortextrecovery'), 'editor_atto'); $PAGE->requires->strings_for_js(array('warning', 'info'), 'moodle'); $PAGE->requires->yui_module($modules, 'Y.M.editor_atto.Editor.init', array($this->get_init_params($elementid, $options, $fpoptions, $jsplugins))); }