/** * 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 object description or false if not found or exception thrown */ 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) ? 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: 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 = 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']; } } return $function; }
/** * 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; } else { $userid = $userorid; $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST); } 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 if (!is_enrolled(context_course::instance($group->courseid), $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 = 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 $DB->set_field('groups', 'timemodified', $member->timeadded, array('id' => $groupid)); //trigger groups events $eventdata = new stdClass(); $eventdata->groupid = $groupid; $eventdata->userid = $userid; $eventdata->component = $member->component; $eventdata->itemid = $member->itemid; events_trigger('groups_member_added', $eventdata); return true; }
/** * Loads the events definitions for the component (from file). If no * events are defined for the component, we simply return an empty array. * * INTERNAL - to be used from eventslib only * * @global object * @param string $component examples: 'moodle', 'mod/forum', 'block/quiz_results' * @return array of capabilities or empty array if not exists */ function events_load_def($component) { $defpath = get_component_directory($component) . '/db/events.php'; $handlers = array(); if (file_exists($defpath)) { require $defpath; } return $handlers; }
/** * Loads the events definitions for the component (from file). If no * events are defined for the component, we simply return an empty array. * * INTERNAL - to be used from eventslib only * * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results' * @return array of capabilities or empty array if not exists */ function events_load_def($component) { global $CFG; if ($component === 'unittest') { $defpath = $CFG->dirroot . '/lib/simpletest/fixtures/events.php'; } else { $defpath = 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; }
/** * Return user information including profile picture + basic site information * Note: * - no capability checking because we return just known information by logged user * @param array $serviceshortnames of service shortnames - the functions of these services will be returned * @return array */ public function get_site_info($serviceshortnames = array()) { global $USER, $SITE, $CFG; $params = self::validate_parameters(self::get_site_info_parameters(), array('serviceshortnames' => $serviceshortnames)); $profileimageurl = moodle_url::make_pluginfile_url(get_context_instance(CONTEXT_USER, $USER->id)->id, 'user', 'icon', NULL, '/', 'f1'); require_once $CFG->dirroot . "/webservice/lib.php"; $webservice = new webservice(); //If no service listed always return the mobile one by default if (empty($params['serviceshortnames']) and $CFG->enablewebservices) { $mobileservice = $webservice->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); if ($mobileservice->enabled) { $params['serviceshortnames'] = array(MOODLE_OFFICIAL_MOBILE_SERVICE); //return mobile service by default } } //retrieve the functions related to the services $functions = $webservice->get_external_functions_by_enabled_services($params['serviceshortnames']); //built up the returned values of the list of functions $componentversions = array(); $avalaiblefunctions = array(); foreach ($functions as $function) { $functioninfo = array(); $functioninfo['name'] = $function->name; if ($function->component == 'moodle') { $version = $CFG->version; //moodle version } else { $versionpath = 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])) { 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; $avalaiblefunctions[] = $functioninfo; } return array('sitename' => $SITE->fullname, 'siteurl' => $CFG->wwwroot, 'username' => $USER->username, 'firstname' => $USER->firstname, 'lastname' => $USER->lastname, 'fullname' => fullname($USER), 'userid' => $USER->id, 'userpictureurl' => $profileimageurl->out(false), 'functions' => $avalaiblefunctions); }
/** * Loads the task definitions for the component (from file). If no * tasks are defined for the component, we simply return an empty array. * @param $component - examples: 'moodle', 'mod_forum', 'block_quiz_results' * @return array of tasks or empty array if not exists * * INTERNAL - to be used from cronlib only */ function elis_tasks_load_def($component) { global $CFG; if ($component == 'moodle') { $defpath = $CFG->libdir . '/db/tasks.php'; //} else if ($component == 'unittest') { // $defpath = $CFG->libdir.'/simpletest/fixtures/tasks.php'; } else { $defpath = get_component_directory($component) . '/db/tasks.php'; //error_log("/local/eliscore/lib/tasklib.php::elis_tasks_load_def('{$component}') looking for: {$defpath}"); } $tasks = array(); if (file_exists($defpath)) { require $defpath; } return $tasks; }
/** * 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(get_component_directory('core'))) { $moodlemodules = array_merge($moodlemodules, $module); } // Handle other core subsystems. $subsystems = get_core_subsystems(); foreach ($subsystems as $subsystem => $path) { if (is_null($path)) { continue; } $path = get_component_directory($subsystem); if ($module = $this->get_moodle_path_metadata($path)) { $moodlemodules = array_merge($moodlemodules, $module); } } // And finally the plugins. $plugintypes = get_plugin_types(); foreach ($plugintypes as $plugintype => $pathroot) { $pluginlist = get_plugin_list($plugintype); foreach ($pluginlist as $plugin => $path) { if ($module = $this->get_moodle_path_metadata($path)) { $moodlemodules = array_merge($moodlemodules, $module); } } } return $moodlemodules; }
/** * Find out if JS module present and return details. * @param string $component name of component in frankenstyle, ex: core_group, mod_forum * @return array description of module or null if not found */ protected function find_module($component) { global $CFG; $module = null; if (strpos($component, 'core_') === 0) { // must be some core stuff - list here is not complete, this is just the stuff used from multiple places // so that we do nto have to repeat the definition of these modules over and over again switch ($component) { case 'core_filepicker': $module = array('name' => 'core_filepicker', 'fullpath' => '/repository/filepicker.js', 'requires' => array('base', 'node', 'node-event-simulate', 'json', 'async-queue', 'io', 'yui2-button', 'yui2-container', 'yui2-layout', 'yui2-menu', 'yui2-treeview', 'yui2-dragdrop', 'yui2-cookie'), 'strings' => array(array('add', 'repository'), array('back', 'repository'), array('cancel', 'moodle'), array('close', 'repository'), array('cleancache', 'repository'), array('copying', 'repository'), array('date', 'repository'), array('downloadsucc', 'repository'), array('emptylist', 'repository'), array('error', 'repository'), array('federatedsearch', 'repository'), array('filenotnull', 'repository'), array('getfile', 'repository'), array('help', 'moodle'), array('iconview', 'repository'), array('invalidjson', 'repository'), array('linkexternal', 'repository'), array('listview', 'repository'), array('loading', 'repository'), array('login', 'repository'), array('logout', 'repository'), array('noenter', 'repository'), array('noresult', 'repository'), array('manageurl', 'repository'), array('popup', 'repository'), array('preview', 'repository'), array('refresh', 'repository'), array('save', 'repository'), array('saveas', 'repository'), array('saved', 'repository'), array('saving', 'repository'), array('search', 'repository'), array('searching', 'repository'), array('size', 'repository'), array('submit', 'repository'), array('sync', 'repository'), array('title', 'repository'), array('upload', 'repository'), array('uploading', 'repository'), array('xhtmlerror', 'repository'), array('cancel'), array('chooselicense', 'repository'), array('author', 'repository'), array('ok', 'moodle'), array('error', 'moodle'), array('info', 'moodle'), array('norepositoriesavailable', 'repository'), array('norepositoriesexternalavailable', 'repository'), array('nofilesattached', 'repository'), array('filepicker', 'repository'), array('nofilesavailable', 'repository'), array('overwrite', 'repository'), array('renameto', 'repository'), array('fileexists', 'repository'), array('fileexistsdialogheader', 'repository'), array('fileexistsdialog_editor', 'repository'), array('fileexistsdialog_filemanager', 'repository'))); break; case 'core_comment': $module = array('name' => 'core_comment', 'fullpath' => '/comment/comment.js', 'requires' => array('base', 'io', 'node', 'json', 'yui2-animation', 'overlay'), 'strings' => array(array('confirmdeletecomments', 'admin'), array('yes', 'moodle'), array('no', 'moodle'))); break; case 'core_role': $module = array('name' => 'core_role', 'fullpath' => '/admin/roles/module.js', 'requires' => array('node', 'cookie')); break; case 'core_completion': $module = array('name' => 'core_completion', 'fullpath' => '/course/completion.js'); break; case 'core_dock': $module = array('name' => 'core_dock', 'fullpath' => '/blocks/dock.js', 'requires' => array('base', 'node', 'event-custom', 'event-mouseenter', 'event-resize'), 'strings' => array(array('addtodock', 'block'), array('undockitem', 'block'), array('undockall', 'block'), array('thisdirectionvertical', 'langconfig'))); break; case 'core_message': $module = array('name' => 'core_message', 'requires' => array('base', 'node', 'event', 'node-event-simulate'), 'fullpath' => '/message/module.js'); break; case 'core_group': $module = array('name' => 'core_group', 'fullpath' => '/group/module.js', 'requires' => array('node', 'overlay', 'event-mouseenter')); break; case 'core_question_engine': $module = array('name' => 'core_question_engine', 'fullpath' => '/question/qengine.js', 'requires' => array('node', 'event')); break; case 'core_rating': $module = array('name' => 'core_rating', 'fullpath' => '/rating/module.js', 'requires' => array('node', 'event', 'overlay', 'io', 'json')); break; case 'core_filetree': $module = array('name' => 'core_filetree', 'fullpath' => '/files/module.js', 'requires' => array('node', 'event', 'overlay', 'io', 'json', 'yui2-treeview')); break; } } else { if ($dir = get_component_directory($component)) { if (file_exists("{$dir}/module.js")) { if (strpos($dir, $CFG->dirroot . '/') === 0) { $dir = substr($dir, strlen($CFG->dirroot)); $module = array('name' => $component, 'fullpath' => "{$dir}/module.js", 'requires' => array()); } } } } return $module; }
/** * 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 = 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; }
} 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); } 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 = 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); } send_file_not_found(); } } } } }
/** * 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)); $profileimageurl = moodle_url::make_pluginfile_url( context_user::instance($USER->id)->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), '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; 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.* FROM {external_functions} f, {external_services_functions} sf 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 = 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])) { 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; return $siteinfo; }
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 = get_component_directory($componentname); list($type, $plugin) = 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 $pathname = $functionname($context, $args); }
/** * Function to require any potential callback files, throwing exceptions * if an issue occurs. * * @param string $callbackfile This is the location of the callback file '/mod/forum/locallib.php' * @param string $class Name of the class containing the callback functions * activity components should ALWAYS use their name_portfolio_caller * other locations must use something unique */ function portfolio_include_callback_file($callbackfile, $class = null) { global $CFG; require_once($CFG->libdir . '/adminlib.php'); // Get the last occurrence of '/' in the file path. $pos = strrpos($callbackfile, '/'); // Get rid of the first slash (if it exists). $callbackfile = ltrim($callbackfile, '/'); // Get a list of valid plugin types. $plugintypes = get_plugin_types(false); // Assume it is not valid for now. $isvalid = false; // Go through the plugin types. foreach ($plugintypes as $type => $path) { if (strrpos($callbackfile, $path) === 0) { // Found the plugin type. $isvalid = true; $plugintype = $type; $pluginpath = $path; } } // Throw exception if not a valid component. if (!$isvalid) { throw new coding_exception('Somehow a non-valid plugin path was passed, could be a hackz0r attempt, exiting.'); } // Keep record of the filename. $filename = substr($callbackfile, $pos); // Remove the file name. $component = trim(substr($callbackfile, 0, $pos), '/'); // Replace the path with the type. $component = str_replace($pluginpath, $plugintype, $component); // Ok, replace '/' with '_'. $component = str_replace('/', '_', $component); // Check that it is a valid component. if (!get_component_version($component)) { throw new portfolio_button_exception('nocallbackcomponent', 'portfolio', '', $component); } // Obtain the component's location. if (!$componentloc = get_component_directory($component)) { throw new portfolio_button_exception('nocallbackcomponent', 'portfolio', '', $component); } // Check if the filename does not meet any of the expected names. if (($filename != 'locallib.php') && ($filename != 'portfoliolib.php') && ($filename != 'portfolio_callback.php')) { debugging('Please standardise your plugin by keeping your portfolio callback functionality in the file locallib.php.', DEBUG_DEVELOPER); } // Throw error if file does not exist. if (!file_exists($componentloc . '/' . $filename)) { throw new portfolio_button_exception('nocallbackfile', 'portfolio', '', $callbackfile); } require_once($componentloc . '/' . $filename); if (!is_null($class) && !class_exists($class)) { throw new portfolio_button_exception('nocallbackclass', 'portfolio', '', $class); } }
/** * 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; if ($filearea === 'questiontext_preview') { $component = array_shift($args); $questionid = array_shift($args); component_callback($component, 'questiontext_preview_pluginfile', array($context, $questionid, $args, $forcedownload, $options)); send_file_not_found(); } 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()); } $qubaid = (int) array_shift($args); $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 = 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(); } }
/** * Web service discovery function used during install and upgrade. * @param string $component name of component (moodle, mod_assignment, etc.) * @return void */ function external_update_descriptions($component) { global $DB; $defpath = get_component_directory($component) . '/db/services.php'; if (!file_exists($defpath)) { external_delete_descriptions($component); return; } // load new info $functions = array(); $services = array(); include $defpath; // update all function fist $dbfunctions = $DB->get_records('external_functions', array('component' => $component)); foreach ($dbfunctions as $dbfunction) { if (empty($functions[$dbfunction->name])) { $DB->delete_records('external_functions', array('id' => $dbfunction->id)); // do not delete functions from external_services_functions, beacuse // we want to notify admins when functions used in custom services disappear //TODO: this looks wrong, we have to delete it eventually (skodak) continue; } $function = $functions[$dbfunction->name]; unset($functions[$dbfunction->name]); $function['classpath'] = empty($function['classpath']) ? null : $function['classpath']; $update = false; if ($dbfunction->classname != $function['classname']) { $dbfunction->classname = $function['classname']; $update = true; } if ($dbfunction->methodname != $function['methodname']) { $dbfunction->methodname = $function['methodname']; $update = true; } if ($dbfunction->classpath != $function['classpath']) { $dbfunction->classpath = $function['classpath']; $update = true; } $functioncapabilities = key_exists('capabilities', $function) ? $function['capabilities'] : ''; if ($dbfunction->capabilities != $functioncapabilities) { $dbfunction->capabilities = $functioncapabilities; $update = true; } if ($update) { $DB->update_record('external_functions', $dbfunction); } } foreach ($functions as $fname => $function) { $dbfunction = new stdClass(); $dbfunction->name = $fname; $dbfunction->classname = $function['classname']; $dbfunction->methodname = $function['methodname']; $dbfunction->classpath = empty($function['classpath']) ? null : $function['classpath']; $dbfunction->component = $component; $dbfunction->capabilities = key_exists('capabilities', $function) ? $function['capabilities'] : ''; $dbfunction->id = $DB->insert_record('external_functions', $dbfunction); } unset($functions); // now deal with services $dbservices = $DB->get_records('external_services', array('component' => $component)); foreach ($dbservices as $dbservice) { if (empty($services[$dbservice->name])) { $DB->delete_records('external_services_functions', array('externalserviceid' => $dbservice->id)); $DB->delete_records('external_services_users', array('externalserviceid' => $dbservice->id)); $DB->delete_records('external_services', array('id' => $dbservice->id)); continue; } $service = $services[$dbservice->name]; unset($services[$dbservice->name]); $service['enabled'] = empty($service['enabled']) ? 0 : $service['enabled']; $service['requiredcapability'] = empty($service['requiredcapability']) ? null : $service['requiredcapability']; $service['restrictedusers'] = !isset($service['restrictedusers']) ? 1 : $service['restrictedusers']; $update = false; if ($dbservice->enabled != $service['enabled']) { $dbservice->enabled = $service['enabled']; $update = true; } if ($dbservice->requiredcapability != $service['requiredcapability']) { $dbservice->requiredcapability = $service['requiredcapability']; $update = true; } if ($dbservice->restrictedusers != $service['restrictedusers']) { $dbservice->restrictedusers = $service['restrictedusers']; $update = true; } if ($update) { $DB->update_record('external_services', $dbservice); } $functions = $DB->get_records('external_services_functions', array('externalserviceid' => $dbservice->id)); foreach ($functions as $function) { $key = array_search($function->functionname, $service['functions']); if ($key === false) { $DB->delete_records('external_services_functions', array('id' => $function->id)); } else { unset($service['functions'][$key]); } } foreach ($service['functions'] as $fname) { $newf = new stdClass(); $newf->externalserviceid = $dbservice->id; $newf->functionname = $fname; $DB->insert_record('external_services_functions', $newf); } unset($functions); } foreach ($services as $name => $service) { $dbservice = new stdClass(); $dbservice->name = $name; $dbservice->enabled = empty($service['enabled']) ? 0 : $service['enabled']; $dbservice->requiredcapability = empty($service['requiredcapability']) ? null : $service['requiredcapability']; $dbservice->restrictedusers = !isset($service['restrictedusers']) ? 1 : $service['restrictedusers']; $dbservice->component = $component; $dbservice->timecreated = time(); $dbservice->id = $DB->insert_record('external_services', $dbservice); foreach ($service['functions'] as $fname) { $newf = new stdClass(); $newf->externalserviceid = $dbservice->id; $newf->functionname = $fname; $DB->insert_record('external_services_functions', $newf); } } }
/** * invoke plugin's callback functions * * @param string $type Plugin type e.g. 'mod' * @param string $name Plugin name * @param string $feature Feature code (FEATURE_xx constant) * @param string $action Feature's action * @param string $options parameters of callback function, should be an array * @param mixed $default default value if callback function hasn't been defined * @return mixed */ function plugin_callback($type, $name, $feature, $action, $options = null, $default=null) { global $CFG; $name = clean_param($name, PARAM_SAFEDIR); $function = $name.'_'.$feature.'_'.$action; $file = get_component_directory($type . '_' . $name) . '/lib.php'; // Load library and look for function if (file_exists($file)) { require_once($file); } if (function_exists($function)) { // Function exists, so just return function result $ret = call_user_func_array($function, (array)$options); if (is_null($ret)) { return $default; } else { return $ret; } } return $default; }
/** * 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->write_close(); // unlock session during fileserving send_stored_file($file, 60 * 60, 0, true, array('preview' => $preview)); } else { send_file_not_found(); } // ======================================================================================================================== } 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(); } // Check that we got an event and that it's userid is that of the user // 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->write_close(); // unlock session during fileserving send_stored_file($file, 60 * 60, 0, $forcedownload, 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 if (!is_enrolled($context) and !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') { //ok } 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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'); send_file($imagefile, basename($imagefile), 60 * 60 * 24 * 14); } send_stored_file($file, 60 * 60 * 24 * 365, 0, false, array('preview' => $preview)); // 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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') { if ($CFG->forcelogin) { require_login(); } $filename = array_pop($args); $filepath = $args ? '/' . implode('/', $args) . '/' : '/'; if (!($file = $fs->get_file($context->id, 'course', 'summary', 0, $filepath, $filename)) or $file->is_directory()) { send_file_not_found(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } if ($course->numsections < $section->section) { if (!has_capability('moodle/course:update', $context)) { // block access to unavailable sections if can not edit course 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(); } session_get_instance()->write_close(); // unlock session during fileserving send_stored_file($file, 60 * 60, 0, $forcedownload, array('preview' => $preview)); } else { 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->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(); } session_get_instance()->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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } session_get_instance()->write_close(); // unlock session during fileserving 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(); } $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400; // finally send the file send_stored_file($file, $lifetime, 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(); } $bprecord = $DB->get_record('block_positions', array('blockinstanceid' => $context->instanceid), 'visible'); // 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 = 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(); } } } } } } } } } } } } } } } }
/** * 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 = 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."; debugging($message); $this->log($message, backup::LOG_WARNING); } } }
/** * Find out if JS module present and return details. * * @param string $component name of component in frankenstyle, ex: core_group, mod_forum * @return array description of module or null if not found */ protected function find_module($component) { global $CFG, $PAGE; $module = null; if (strpos($component, 'core_') === 0) { // Must be some core stuff - list here is not complete, this is just the stuff used from multiple places // so that we do nto have to repeat the definition of these modules over and over again. switch ($component) { case 'core_filepicker': $module = array('name' => 'core_filepicker', 'fullpath' => '/repository/filepicker.js', 'requires' => array('base', 'node', 'node-event-simulate', 'json', 'async-queue', 'io-base', 'io-upload-iframe', 'io-form', 'yui2-treeview', 'panel', 'cookie', 'datatable', 'datatable-sort', 'resize-plugin', 'dd-plugin', 'moodle-core_filepicker'), 'strings' => array(array('lastmodified', 'moodle'), array('name', 'moodle'), array('type', 'repository'), array('size', 'repository'), array('invalidjson', 'repository'), array('error', 'moodle'), array('info', 'moodle'), array('nofilesattached', 'repository'), array('filepicker', 'repository'), array('logout', 'repository'), array('nofilesavailable', 'repository'), array('norepositoriesavailable', 'repository'), array('fileexistsdialogheader', 'repository'), array('fileexistsdialog_editor', 'repository'), array('fileexistsdialog_filemanager', 'repository'), array('renameto', 'repository'), array('referencesexist', 'repository'))); break; case 'core_comment': $module = array('name' => 'core_comment', 'fullpath' => '/comment/comment.js', 'requires' => array('base', 'io-base', 'node', 'json', 'yui2-animation', 'overlay'), 'strings' => array(array('confirmdeletecomments', 'admin'), array('yes', 'moodle'), array('no', 'moodle'))); break; case 'core_role': $module = array('name' => 'core_role', 'fullpath' => '/admin/roles/module.js', 'requires' => array('node', 'cookie')); break; case 'core_completion': $module = array('name' => 'core_completion', 'fullpath' => '/course/completion.js'); break; case 'core_dock': $module = array('name' => 'core_dock', 'fullpath' => '/blocks/dock.js', 'requires' => array('base', 'node', 'event-custom', 'event-mouseenter', 'event-resize'), 'strings' => array(array('addtodock', 'block'), array('undockitem', 'block'), array('undockall', 'block'), array('thisdirectionvertical', 'langconfig'))); break; case 'core_message': $module = array('name' => 'core_message', 'requires' => array('base', 'node', 'event', 'node-event-simulate'), 'fullpath' => '/message/module.js'); break; case 'core_group': $module = array('name' => 'core_group', 'fullpath' => '/group/module.js', 'requires' => array('node', 'overlay', 'event-mouseenter')); break; case 'core_question_engine': $module = array('name' => 'core_question_engine', 'fullpath' => '/question/qengine.js', 'requires' => array('node', 'event')); break; case 'core_rating': $module = array('name' => 'core_rating', 'fullpath' => '/rating/module.js', 'requires' => array('node', 'event', 'overlay', 'io-base', 'json')); break; case 'core_dndupload': $module = array('name' => 'core_dndupload', 'fullpath' => '/lib/form/dndupload.js', 'requires' => array('node', 'event', 'json', 'core_filepicker'), 'strings' => array(array('uploadformlimit', 'moodle'), array('droptoupload', 'moodle'), array('maxfilesreached', 'moodle'), array('dndenabled_inbox', 'moodle'), array('fileexists', 'moodle'))); break; } } else { if ($dir = get_component_directory($component)) { if (file_exists("{$dir}/module.js")) { if (strpos($dir, $CFG->dirroot . '/') === 0) { $dir = substr($dir, strlen($CFG->dirroot)); $module = array('name' => $component, 'fullpath' => "{$dir}/module.js", 'requires' => array()); } } } } return $module; }
/** * 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) = 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 = 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]; }
/** * Automatically clean-up all plugin data and remove the plugin DB tables * * @param string $type The plugin type, eg. 'mod', 'qtype', 'workshopgrading' etc. * @param string $name The plugin name, eg. 'forum', 'multichoice', 'accumulative' etc. * @uses global $OUTPUT to produce notices and other messages * @return void */ function uninstall_plugin($type, $name) { global $CFG, $DB, $OUTPUT; // recursively uninstall all module/editor subplugins first if ($type === 'mod' || $type === 'editor') { $base = get_component_directory($type . '_' . $name); if (file_exists("{$base}/db/subplugins.php")) { $subplugins = array(); include "{$base}/db/subplugins.php"; foreach ($subplugins as $subplugintype => $dir) { $instances = get_plugin_list($subplugintype); foreach ($instances as $subpluginname => $notusedpluginpath) { uninstall_plugin($subplugintype, $subpluginname); } } } } $component = $type . '_' . $name; // eg. 'qtype_multichoice' or 'workshopgrading_accumulative' or 'mod_forum' if ($type === 'mod') { $pluginname = $name; // eg. 'forum' if (get_string_manager()->string_exists('modulename', $component)) { $strpluginname = get_string('modulename', $component); } else { $strpluginname = $component; } } else { $pluginname = $component; if (get_string_manager()->string_exists('pluginname', $component)) { $strpluginname = get_string('pluginname', $component); } else { $strpluginname = $component; } } echo $OUTPUT->heading($pluginname); $plugindirectory = get_plugin_directory($type, $name); $uninstalllib = $plugindirectory . '/db/uninstall.php'; if (file_exists($uninstalllib)) { require_once $uninstalllib; $uninstallfunction = 'xmldb_' . $pluginname . '_uninstall'; // eg. 'xmldb_workshop_uninstall()' if (function_exists($uninstallfunction)) { if (!$uninstallfunction()) { echo $OUTPUT->notification('Encountered a problem running uninstall function for ' . $pluginname); } } } if ($type === 'mod') { // perform cleanup tasks specific for activity modules if (!($module = $DB->get_record('modules', array('name' => $name)))) { print_error('moduledoesnotexist', 'error'); } // delete all the relevant instances from all course sections if ($coursemods = $DB->get_records('course_modules', array('module' => $module->id))) { foreach ($coursemods as $coursemod) { if (!delete_mod_from_section($coursemod->id, $coursemod->section)) { echo $OUTPUT->notification("Could not delete the {$strpluginname} with id = {$coursemod->id} from section {$coursemod->section}"); } } } // clear course.modinfo for courses that used this module $sql = "UPDATE {course}\n SET modinfo=''\n WHERE id IN (SELECT DISTINCT course\n FROM {course_modules}\n WHERE module=?)"; $DB->execute($sql, array($module->id)); // delete all the course module records $DB->delete_records('course_modules', array('module' => $module->id)); // delete module contexts if ($coursemods) { foreach ($coursemods as $coursemod) { if (!delete_context(CONTEXT_MODULE, $coursemod->id)) { echo $OUTPUT->notification("Could not delete the context for {$strpluginname} with id = {$coursemod->id}"); } } } // delete the module entry itself $DB->delete_records('modules', array('name' => $module->name)); // cleanup the gradebook require_once $CFG->libdir . '/gradelib.php'; grade_uninstalled_module($module->name); // Perform any custom uninstall tasks if (file_exists($CFG->dirroot . '/mod/' . $module->name . '/lib.php')) { require_once $CFG->dirroot . '/mod/' . $module->name . '/lib.php'; $uninstallfunction = $module->name . '_uninstall'; if (function_exists($uninstallfunction)) { debugging("{$uninstallfunction}() has been deprecated. Use the plugin's db/uninstall.php instead", DEBUG_DEVELOPER); if (!$uninstallfunction()) { echo $OUTPUT->notification('Encountered a problem running uninstall function for ' . $module->name . '!'); } } } } else { if ($type === 'enrol') { // NOTE: this is a bit brute force way - it will not trigger events and hooks properly // nuke all role assignments role_unassign_all(array('component' => $component)); // purge participants $DB->delete_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($name)); // purge enrol instances $DB->delete_records('enrol', array('enrol' => $name)); // tweak enrol settings if (!empty($CFG->enrol_plugins_enabled)) { $enabledenrols = explode(',', $CFG->enrol_plugins_enabled); $enabledenrols = array_unique($enabledenrols); $enabledenrols = array_flip($enabledenrols); unset($enabledenrols[$name]); $enabledenrols = array_flip($enabledenrols); if (is_array($enabledenrols)) { set_config('enrol_plugins_enabled', implode(',', $enabledenrols)); } } } else { if ($type === 'block') { if ($block = $DB->get_record('block', array('name' => $name))) { // Inform block it's about to be deleted if (file_exists("{$CFG->dirroot}/blocks/{$block->name}/block_{$block->name}.php")) { $blockobject = block_instance($block->name); if ($blockobject) { $blockobject->before_delete(); //only if we can create instance, block might have been already removed } } // First delete instances and related contexts $instances = $DB->get_records('block_instances', array('blockname' => $block->name)); foreach ($instances as $instance) { blocks_delete_instance($instance); } // Delete block $DB->delete_records('block', array('id' => $block->id)); } } } } // perform clean-up task common for all the plugin/subplugin types //delete the web service functions and pre-built services require_once $CFG->dirroot . '/lib/externallib.php'; external_delete_descriptions($component); // delete calendar events $DB->delete_records('event', array('modulename' => $pluginname)); // delete all the logs $DB->delete_records('log', array('module' => $pluginname)); // delete log_display information $DB->delete_records('log_display', array('component' => $component)); // delete the module configuration records unset_all_config_for_plugin($pluginname); // delete message provider message_provider_uninstall($component); // delete message processor if ($type === 'message') { message_processor_uninstall($name); } // delete the plugin tables $xmldbfilepath = $plugindirectory . '/db/install.xml'; drop_plugin_tables($component, $xmldbfilepath, false); if ($type === 'mod' or $type === 'block') { // non-frankenstyle table prefixes drop_plugin_tables($name, $xmldbfilepath, false); } // delete the capabilities that were defined by this module capabilities_cleanup($component); // remove event handlers and dequeue pending events events_uninstall($component); echo $OUTPUT->notification(get_string('success'), 'notifysuccess'); }
/** * Function to require any potential callback files, throwing exceptions * if an issue occurs. * * @param string $component This is the name of the component in Moodle, eg 'mod_forum' * @param string $class Name of the class containing the callback functions * activity components should ALWAYS use their name_portfolio_caller * other locations must use something unique */ function portfolio_include_callback_file($component, $class = null) { global $CFG; require_once $CFG->libdir . '/adminlib.php'; // It's possible that they are passing a file path rather than passing a component. // We want to try and convert this to a component name, eg. mod_forum. $pos = strrpos($component, '/'); if ($pos !== false) { // Get rid of the first slash (if it exists). $component = ltrim($component, '/'); // Get a list of valid plugin types. $plugintypes = get_plugin_types(false); // Assume it is not valid for now. $isvalid = false; // Go through the plugin types. foreach ($plugintypes as $type => $path) { if (strrpos($component, $path) === 0) { // Found the plugin type. $isvalid = true; $plugintype = $type; $pluginpath = $path; } } // Throw exception if not a valid component. if (!$isvalid) { throw new coding_exception('Somehow a non-valid plugin path was passed, could be a hackz0r attempt, exiting.'); } // Remove the file name. $component = trim(substr($component, 0, $pos), '/'); // Replace the path with the type. $component = str_replace($pluginpath, $plugintype, $component); // Ok, replace '/' with '_'. $component = str_replace('/', '_', $component); // Place a debug message saying the third parameter should be changed. debugging('The third parameter sent to the function set_callback_options should be the component name, not a file path, please update this.', DEBUG_DEVELOPER); } // Check that it is a valid component. if (!get_component_version($component)) { throw new portfolio_button_exception('nocallbackcomponent', 'portfolio', '', $component); } // Obtain the component's location. if (!($componentloc = get_component_directory($component))) { throw new portfolio_button_exception('nocallbackcomponent', 'portfolio', '', $component); } // Check if the component contains the necessary file for the portfolio plugin. // These are locallib.php, portfoliolib.php and portfolio_callback.php. $filefound = false; if (file_exists($componentloc . '/locallib.php')) { $filefound = true; require_once $componentloc . '/locallib.php'; } if (file_exists($componentloc . '/portfoliolib.php')) { $filefound = true; debugging('Please standardise your plugin by renaming your portfolio callback file to locallib.php, or if that file already exists moving the portfolio functionality there.', DEBUG_DEVELOPER); require_once $componentloc . '/portfoliolib.php'; } if (file_exists($componentloc . '/portfolio_callback.php')) { $filefound = true; debugging('Please standardise your plugin by renaming your portfolio callback file to locallib.php, or if that file already exists moving the portfolio functionality there.', DEBUG_DEVELOPER); require_once $componentloc . '/portfolio_callback.php'; } // Ensure that we found a file we can use, if not throw an exception. if (!$filefound) { throw new portfolio_button_exception('nocallbackfile', 'portfolio', '', $component); } if (!is_null($class) && !class_exists($class)) { throw new portfolio_button_exception('nocallbackclass', 'portfolio', '', $class); } }
private function recreate_table($component, $tablename) { global $DB; unset($DB->donesetup); $manager = $DB->get_manager(); $filename = get_component_directory($component) . "/db/install.xml"; $xmldbfile = new xmldb_file($filename); if (!$xmldbfile->fileExists()) { throw new ddl_exception('ddlxmlfileerror', null, 'File does not exist'); } $loaded = $xmldbfile->loadXMLStructure(); if (!$loaded || !$xmldbfile->isLoaded()) { // Show info about the error if we can find it. if ($structure =& $xmldbfile->getStructure()) { if ($errors = $structure->getAllErrors()) { throw new ddl_exception('ddlxmlfileerror', null, 'Errors found in XMLDB file: ' . implode(', ', $errors)); } } throw new ddl_exception('ddlxmlfileerror', null, 'not loaded??'); } $structure = $xmldbfile->getStructure(); $table = $structure->getTable($tablename); $manager->create_table($table); $DB->donesetup = true; }
/** * 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) = 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 if ($plugintype === 'mod') { try { $currentversion = $DB->get_field('modules', 'version', array('name'=>$pluginname)); $currentversion = ($currentversion === false) ? null : $currentversion; } catch (Exception $ignored) { } $cd = get_component_directory($component); if (file_exists("$cd/version.php")) { $module = new stdClass(); $module->version = null; include("$cd/version.php"); $targetversion = $module->version; } } else if ($plugintype === 'block') { try { if ($block = $DB->get_record('block', array('name'=>$pluginname))) { $currentversion = $block->version; } } catch (Exception $ignored) { } $cd = get_component_directory($component); if (file_exists("$cd/version.php")) { $plugin = new stdClass(); $plugin->version = null; include("$cd/version.php"); $targetversion = $plugin->version; } } else { $pluginversion = get_config($component, 'version'); if (!empty($pluginversion)) { $currentversion = $pluginversion; } $cd = get_component_directory($component); if (file_exists("$cd/version.php")) { $plugin = new stdClass(); $plugin->version = null; 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 } }
continue; } //debug($bits); $version = array_shift($bits); if ($version == 'moodle') { //TODO: this is a ugly hack because we should not load any libs here! define('MOODLE_INTERNAL', true); require_once $CFG->libdir . '/moodlelib.php'; $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); $dir = get_component_directory($frankenstyle); if ($mimetype == 'text/css') { $bits[] = 'assets'; $bits[] = 'skins'; $bits[] = 'sam'; } $contentfile = $dir . '/yui/' . join('/', $bits) . '/' . $filename; } else { if ($version != $CFG->yui3version and $version != $CFG->yui2version and $version != 'gallery') { $content .= "\n// Wrong yui version {$part}!\n"; continue; } $contentfile = "{$CFG->libdir}/yui/{$part}"; } if (!file_exists($contentfile) or !is_file($contentfile)) { $content .= "\n// Combo resource {$part} not found!\n";
public function test_deprecated_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, get_component_directory($plugintype . '_' . $pluginname)); } } $subsystems = core_component::get_core_subsystems(); foreach ($subsystems as $subsystem => $fulldir) { $this->assertSame($fulldir, get_component_directory('core_' . $subsystem)); } }
/** * 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 = 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 . '...'); $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); } }
/** * 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. * * @param object $course course settings object * @param object $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. */ function question_pluginfile($course, $context, $component, $filearea, $args, $forcedownload) { global $DB, $CFG; list($context, $course, $cm) = get_context_info_array($context->id); require_login($course, false, $cm); if ($filearea === 'export') { 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(); } //DEBUG //echo '<textarea cols=90 rows=20>'; //echo $content; //echo '</textarea>'; //die; send_file($content, $filename, 0, 0, true, true, $qformat->mime_type()); } $attemptid = (int) array_shift($args); $questionid = (int) array_shift($args); if ($attemptid === 0) { // preview require_once $CFG->dirroot . '/question/previewlib.php'; return question_preview_question_pluginfile($course, $context, $component, $filearea, $attemptid, $questionid, $args, $forcedownload); } else { $module = $DB->get_field('question_attempts', 'modulename', array('id' => $attemptid)); $dir = 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)) { send_file_not_found(); } $filefunction($course, $context, $component, $filearea, $attemptid, $questionid, $args, $forcedownload); send_file_not_found(); } }
/** * 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 = 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); }
/** * Invoke component's callback functions * * @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' * @param array $params parameters of callback function * @param mixed $default default value if callback function hasn't been defined, or if it retursn null. * @return mixed */ function component_callback($component, $function, array $params = array(), $default = null) { global $CFG; // this is needed for require_once() below $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) = normalize_component($component); $component = $type . '_' . $name; $oldfunction = $name . '_' . $function; $function = $component . '_' . $function; $dir = 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}"); } $function = $oldfunction; } if (function_exists($function)) { // Function exists, so just return function result $ret = call_user_func_array($function, $params); if (is_null($ret)) { return $default; } else { return $ret; } } return $default; }