/** * Constructor, this constructor should be called ONLY from the file_storage class! * * @param file_storage $fs file storage instance * @param stdClass $file_record description of file * @param string $filedir location of file directory with sh1 named content files */ public function __construct(file_storage $fs, stdClass $file_record, $filedir) { global $DB, $CFG; $this->fs = $fs; $this->file_record = clone $file_record; // prevent modifications $this->filedir = $filedir; // keep secret, do not expose! if (!empty($file_record->repositoryid)) { require_once "{$CFG->dirroot}/repository/lib.php"; $this->repository = repository::get_repository_by_id($file_record->repositoryid, SYSCONTEXTID); if ($this->repository->supported_returntypes() & FILE_REFERENCE != FILE_REFERENCE) { // Repository cannot do file reference. throw new moodle_exception('error'); } } else { $this->repository = null; } // make sure all reference fields exist in file_record even when it is not a reference foreach (array('referencelastsync', 'referencefileid', 'reference', 'repositoryid') as $key) { if (empty($this->file_record->{$key})) { $this->file_record->{$key} = null; } } }
/** * Constructor, this constructor should be called ONLY from the file_storage class! * * @param file_storage $fs file storage instance * @param stdClass $file_record description of file * @param string $filedir location of file directory with sh1 named content files */ public function __construct(file_storage $fs, stdClass $file_record, $filedir) { global $DB, $CFG; $this->fs = $fs; $this->file_record = clone $file_record; // prevent modifications $this->filedir = $filedir; // keep secret, do not expose! if (!empty($file_record->repositoryid)) { require_once "{$CFG->dirroot}/repository/lib.php"; $this->repository = repository::get_repository_by_id($file_record->repositoryid, SYSCONTEXTID); if ($this->repository->supported_returntypes() & FILE_REFERENCE != FILE_REFERENCE) { // Repository cannot do file reference. throw new moodle_exception('error'); } } else { $this->repository = null; } }
/** * Choose the repository instance that should handle the alias. * * At the same site, we can rely on repository instance id and we just * check it still exists. On other site, try to find matching Server files or * Legacy course files repository instance. Return null if no matching * repository instance can be found. * * @param stdClass $info * @return repository|null */ private function choose_repository(stdClass $info) { global $DB, $CFG; require_once $CFG->dirroot . '/repository/lib.php'; if ($this->task->is_samesite()) { // We can rely on repository instance id. if (array_key_exists($info->oldfile->repositoryid, $this->cachereposbyid)) { return $this->cachereposbyid[$info->oldfile->repositoryid]; } $this->log('looking for repository instance by id', backup::LOG_DEBUG, $info->oldfile->repositoryid, 1); try { $this->cachereposbyid[$info->oldfile->repositoryid] = repository::get_repository_by_id($info->oldfile->repositoryid, SYSCONTEXTID); return $this->cachereposbyid[$info->oldfile->repositoryid]; } catch (Exception $e) { $this->cachereposbyid[$info->oldfile->repositoryid] = null; return null; } } else { // We can rely on repository type only. if (empty($info->oldfile->repositorytype)) { return null; } if (array_key_exists($info->oldfile->repositorytype, $this->cachereposbytype)) { return $this->cachereposbytype[$info->oldfile->repositorytype]; } $this->log('looking for repository instance by type', backup::LOG_DEBUG, $info->oldfile->repositorytype, 1); // Both Server files and Legacy course files repositories have a single // instance at the system context to use. Let us try to find it. if ($info->oldfile->repositorytype === 'local' or $info->oldfile->repositorytype === 'coursefiles') { $sql = "SELECT ri.id\n FROM {repository} r\n JOIN {repository_instances} ri ON ri.typeid = r.id\n WHERE r.type = ? AND ri.contextid = ?"; $ris = $DB->get_records_sql($sql, array($info->oldfile->repositorytype, SYSCONTEXTID)); if (empty($ris)) { return null; } $repoids = array_keys($ris); $repoid = reset($repoids); try { $this->cachereposbytype[$info->oldfile->repositorytype] = repository::get_repository_by_id($repoid, SYSCONTEXTID); return $this->cachereposbytype[$info->oldfile->repositorytype]; } catch (Exception $e) { $this->cachereposbytype[$info->oldfile->repositorytype] = null; return null; } } $this->cachereposbytype[$info->oldfile->repositorytype] = null; return null; } }
/** * Delete all the instances associated to a context. * * This method is intended to be a callback when deleting * a course or a user to delete all the instances associated * to their context. The usual way to delete a single instance * is to use {@link self::delete()}. * * @param int $contextid context ID. * @param boolean $downloadcontents true to convert references to hard copies. * @return void */ public static final function delete_all_for_context($contextid, $downloadcontents = true) { global $DB; $repoids = $DB->get_fieldset_select('repository_instances', 'id', 'contextid = :contextid', array('contextid' => $contextid)); if ($downloadcontents) { foreach ($repoids as $repoid) { $repo = repository::get_repository_by_id($repoid, $contextid); $repo->convert_references_to_local(); } } cache::make('core', 'repositories')->purge(); $DB->delete_records_list('repository_instances', 'id', $repoids); $DB->delete_records_list('repository_instance_config', 'instanceid', $repoids); }
$sourcefield = $repo->get_file_source_info($source); $record->source = $repo::build_source_field($sourcefield); // If file is already a reference, set $source = file source, $repo = file repository // note that in this case user may not have permission to access the source file directly // so no file_browser/file_info can be used below if ($repo->has_moodle_files()) { $file = repository::get_moodle_file($source); if ($file && $file->is_external_file()) { $sourcefield = $file->get_source(); // remember the original source $record->source = $repo::build_source_field($sourcefield); $record->contenthash = $file->get_contenthash(); $record->filesize = $file->get_filesize(); $reference = $file->get_reference(); $repo_id = $file->get_repository_id(); $repo = repository::get_repository_by_id($repo_id, $contextid, $repooptions); } } if ($usefilereference) { if ($repo->has_moodle_files()) { $sourcefile = repository::get_moodle_file($reference); $record->contenthash = $sourcefile->get_contenthash(); $record->filesize = $sourcefile->get_filesize(); } // Check if file exists. if (repository::draftfile_exists($itemid, $saveas_path, $saveas_filename)) { // File name being used, rename it. $unused_filename = repository::get_unused_filename($itemid, $saveas_path, $saveas_filename); $record->filename = $unused_filename; // Create a file copy using unused filename. $storedfile = $fs->create_file_from_reference($record, $repo_id, $reference);
public function validation($data, $files) { global $CFG, $USER; $errors = parent::validation($data, $files); $type = $data['scormtype']; if ($type === SCORM_TYPE_LOCAL) { if (empty($data['packagefile'])) { $errors['packagefile'] = get_string('required'); } else { $draftitemid = file_get_submitted_draft_itemid('packagefile'); file_prepare_draft_area($draftitemid, $this->context->id, 'mod_scorm', 'packagefilecheck', null, array('subdirs' => 0, 'maxfiles' => 1)); // Get file from users draft area. $usercontext = context_user::instance($USER->id); $fs = get_file_storage(); $files = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id', false); if (count($files) < 1) { $errors['packagefile'] = get_string('required'); return $errors; } $file = reset($files); if (!$file->is_external_file() && !empty($data['updatefreq'])) { // Make sure updatefreq is not set if using normal local file. $errors['updatefreq'] = get_string('updatefreq_error', 'mod_scorm'); } if (strtolower($file->get_filename()) == 'imsmanifest.xml') { if (!$file->is_external_file()) { $errors['packagefile'] = get_string('aliasonly', 'mod_scorm'); } else { $repository = repository::get_repository_by_id($file->get_repository_id(), context_system::instance()); if (!$repository->supports_relative_file()) { $errors['packagefile'] = get_string('repositorynotsupported', 'mod_scorm'); } } } else { if (strtolower(substr($file->get_filename(), -3)) == 'xml') { $errors['packagefile'] = get_string('invalidmanifestname', 'mod_scorm'); } else { // Validate this SCORM package. $errors = array_merge($errors, scorm_validate_package($file)); } } } } else { if ($type === SCORM_TYPE_EXTERNAL) { $reference = $data['packageurl']; // Syntax check. if (!preg_match('/(http:\\/\\/|https:\\/\\/|www).*\\/imsmanifest.xml$/i', $reference)) { $errors['packageurl'] = get_string('invalidurl', 'scorm'); } else { // Availability check. $result = scorm_check_url($reference); if (is_string($result)) { $errors['packageurl'] = $result; } } } else { if ($type === 'packageurl') { $reference = $data['reference']; // Syntax check. if (!preg_match('/(http:\\/\\/|https:\\/\\/|www).*(\\.zip|\\.pif)$/i', $reference)) { $errors['packageurl'] = get_string('invalidurl', 'scorm'); } else { // Availability check. $result = scorm_check_url($reference); if (is_string($result)) { $errors['packageurl'] = $result; } } } else { if ($type === SCORM_TYPE_AICCURL) { $reference = $data['packageurl']; // Syntax check. if (!preg_match('/(http:\\/\\/|https:\\/\\/|www).*/', $reference)) { $errors['packageurl'] = get_string('invalidurl', 'scorm'); } else { // Availability check. $result = scorm_check_url($reference); if (is_string($result)) { $errors['packageurl'] = $result; } } } } } } return $errors; }
function test_delete_all_for_context() { global $DB; $this->resetAfterTest(true); $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(); $user = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->create_repository_type('flickr_public'); $this->getDataGenerator()->create_repository_type('filesystem'); $coursecontext = context_course::instance($course->id); $usercontext = context_user::instance($user->id); // Creating course instances. $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $coursecontext->id)); $courserepo1 = repository::get_repository_by_id($repo->id, $coursecontext); $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); $repo = $this->getDataGenerator()->create_repository('filesystem', array('contextid' => $coursecontext->id)); $courserepo2 = repository::get_repository_by_id($repo->id, $coursecontext); $this->assertEquals(2, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); // Creating user instances. $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $usercontext->id)); $userrepo1 = repository::get_repository_by_id($repo->id, $usercontext); $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); $repo = $this->getDataGenerator()->create_repository('filesystem', array('contextid' => $usercontext->id)); $userrepo2 = repository::get_repository_by_id($repo->id, $usercontext); $this->assertEquals(2, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); // Simulation of course deletion. repository::delete_all_for_context($coursecontext->id); $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $courserepo1->id))); $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $courserepo2->id))); $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $courserepo1->id))); $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $courserepo2->id))); // Simulation of user deletion. repository::delete_all_for_context($usercontext->id); $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $userrepo1->id))); $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $userrepo2->id))); $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $userrepo1->id))); $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $userrepo2->id))); // Checking deletion upon course context deletion. $course = $this->getDataGenerator()->create_course(); $coursecontext = context_course::instance($course->id); $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $coursecontext->id)); $courserepo = repository::get_repository_by_id($repo->id, $coursecontext); $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); $coursecontext->delete(); $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); // Checking deletion upon user context deletion. $user = $this->getDataGenerator()->create_user(); $usercontext = context_user::instance($user->id); $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $usercontext->id)); $userrepo = repository::get_repository_by_id($repo->id, $usercontext); $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); $usercontext->delete(); $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); // Checking deletion upon course deletion. $course = $this->getDataGenerator()->create_course(); $coursecontext = context_course::instance($course->id); $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $coursecontext->id)); $courserepo = repository::get_repository_by_id($repo->id, $coursecontext); $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); delete_course($course, false); $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); // Checking deletion upon user deletion. $user = $this->getDataGenerator()->create_user(); $usercontext = context_user::instance($user->id); $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $usercontext->id)); $userrepo = repository::get_repository_by_id($repo->id, $usercontext); $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); delete_user($user); $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); }
/** * Generates and sends the thumbnail for an image in filesystem. * * @param stdClass $course course object * @param stdClass $cm course module object * @param stdClass $context context object * @param string $filearea file area * @param array $args extra arguments * @param bool $forcedownload whether or not force download * @param array $options additional options affecting the file serving * @return bool */ function repository_filesystem_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) { global $OUTPUT, $CFG; // Allowed filearea is either thumb or icon - size of the thumbnail. if ($filearea !== 'thumb' && $filearea !== 'icon') { return false; } // As itemid we pass repository instance id. $itemid = array_shift($args); // Filename is some token that we can ignore (used only to make sure browser does not serve cached copy when file is changed). array_pop($args); // As filepath we use full filepath (dir+name) of the file in this instance of filesystem repository. $filepath = implode('/', $args); // Make sure file exists in the repository and is accessible. $repo = repository::get_repository_by_id($itemid, $context); $repo->check_capability(); // Find stored or generated thumbnail. if (!($file = $repo->get_thumbnail($filepath, $filearea))) { // Generation failed, redirect to default icon for file extension. redirect($OUTPUT->pix_url(file_extension_icon($file, 90))); } // The thumbnails should not be changing much, but maybe the default lifetime is too long. $lifetime = $CFG->filelifetime; if ($lifetime > 60 * 10) { $lifetime = 60 * 10; } send_stored_file($file, $lifetime, 0, $forcedownload, $options); }
/** * get_real_path * * @param object $file * @param object $hotpot (optional, default=null) * @return string */ public static function get_real_path($file, $hotpot = null) { global $CFG, $PAGE; // sanity check if (empty($file)) { return ''; } // set default path (= cached file in filedir) $hash = $file->get_contenthash(); $path = $CFG->dataroot . '/filedir/' . $hash[0] . $hash[1] . '/' . $hash[2] . $hash[3] . '/' . $hash; if (!method_exists($file, 'get_repository_id')) { return $path; // Moodle <= 2.2 } if (!($repositoryid = $file->get_repository_id())) { return $path; // shoudn't happen !! } if (!($repository = repository::get_repository_by_id($repositoryid, $PAGE->context))) { return $path; // shouldn't happen } // get repository $type switch (true) { case isset($repository->options['type']): $type = $repository->options['type']; break; case isset($repository->instance->typeid): $type = repository::get_type_by_id($repository->instance->typeid); $type = $type->get_typename(); break; default: $type = ''; // shouldn't happen !! } // get path according to repository $type switch ($type) { case 'filesystem': if (method_exists($repository, 'get_rootpath')) { $path = $repository->get_rootpath() . '/' . $file->get_reference(); } else { if (isset($repository->root_path)) { $path = $repository->root_path . '/' . $file->get_reference(); } } break; case 'user': case 'coursefiles': // use the the default $path break; } return $path; }
// Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This script displays one thumbnail of the image in current user's dropbox. * If {@link repository_dropbox::send_thumbnail()} can not display image * the default 64x64 filetype icon is returned * * @package repository_dropbox * @copyright 2012 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once dirname(dirname(dirname(__FILE__))) . '/config.php'; require_once dirname(__FILE__) . '/lib.php'; $repo_id = optional_param('repo_id', 0, PARAM_INT); // Repository ID $contextid = optional_param('ctx_id', SYSCONTEXTID, PARAM_INT); // Context ID $source = optional_param('source', '', PARAM_TEXT); // File path in current user's dropbox if (isloggedin() && $repo_id && $source && ($repo = repository::get_repository_by_id($repo_id, $contextid)) && method_exists($repo, 'send_thumbnail')) { // try requesting thumbnail and outputting it. This function exits if thumbnail was retrieved $repo->send_thumbnail($source); } // send default icon for the file type $fileicon = file_extension_icon($source, 64); send_file($CFG->dirroot . '/pix/' . $fileicon . '.png', basename($fileicon) . '.png');
public function test_can_be_edited_by_user() { $this->resetAfterTest(true); $syscontext = context_system::instance(); $course = $this->getDataGenerator()->create_course(); $coursecontext = context_course::instance($course->id); $roleid = create_role('A role', 'arole', 'A role', ''); set_role_contextlevels($roleid, array($syscontext->contextlevel, $coursecontext->contextlevel)); $user = $this->getDataGenerator()->create_user(); $this->setUser($user); $plugintype = new repository_type('flickr_public'); $plugintype->create(true); $params = array( 'name' => 'Flickr Public' ); // Instance on a site level. $repoid = repository::static_function('flickr_public', 'create', 'flickr_public', 0, $syscontext, $params); $systemrepo = repository::get_repository_by_id($repoid, $syscontext); role_assign($roleid, $user->id, $syscontext->id); assign_capability('moodle/site:config', CAP_ALLOW, $roleid, $syscontext, true); assign_capability('repository/flickr_public:view', CAP_ALLOW, $roleid, $syscontext, true); accesslib_clear_all_caches_for_unit_testing(); $this->assertTrue($systemrepo->can_be_edited_by_user()); assign_capability('repository/flickr_public:view', CAP_PROHIBIT, $roleid, $syscontext, true); assign_capability('moodle/site:config', CAP_PROHIBIT, $roleid, $syscontext, true); accesslib_clear_all_caches_for_unit_testing(); $this->assertFalse($systemrepo->can_be_edited_by_user()); assign_capability('repository/flickr_public:view', CAP_ALLOW, $roleid, $syscontext, true); assign_capability('moodle/site:config', CAP_PROHIBIT, $roleid, $syscontext, true); accesslib_clear_all_caches_for_unit_testing(); $this->assertFalse($systemrepo->can_be_edited_by_user()); role_unassign($roleid, $user->id, $syscontext->id); accesslib_clear_all_caches_for_unit_testing(); // Instance on a course level. $this->getDataGenerator()->enrol_user($user->id, $course->id, $roleid); $repoid = repository::static_function('flickr_public', 'create', 'flickr_public', 0, $coursecontext, $params); $courserepo = repository::get_repository_by_id($repoid, $coursecontext); assign_capability('moodle/course:update', CAP_ALLOW, $roleid, $coursecontext, true); assign_capability('repository/flickr_public:view', CAP_ALLOW, $roleid, $coursecontext, true); accesslib_clear_all_caches_for_unit_testing(); $this->assertTrue($courserepo->can_be_edited_by_user()); assign_capability('repository/flickr_public:view', CAP_PROHIBIT, $roleid, $coursecontext, true); accesslib_clear_all_caches_for_unit_testing(); $this->assertFalse($courserepo->can_be_edited_by_user()); assign_capability('moodle/course:update', CAP_ALLOW, $roleid, $coursecontext, true); assign_capability('repository/flickr_public:view', CAP_PROHIBIT, $roleid, $coursecontext, true); accesslib_clear_all_caches_for_unit_testing(); $this->assertFalse($courserepo->can_be_edited_by_user()); role_unassign($roleid, $user->id, $coursecontext->id); accesslib_clear_all_caches_for_unit_testing(); // Instance on a user level. $otheruser = $this->getDataGenerator()->create_user(); $otherusercontext = context_user::instance($otheruser->id); role_assign($roleid, $user->id, $syscontext->id); assign_capability('repository/flickr_public:view', CAP_ALLOW, $roleid, $syscontext, true); accesslib_clear_all_caches_for_unit_testing(); // Editing someone else's instance. $repoid = repository::static_function('flickr_public', 'create', 'flickr_public', 0, $otherusercontext, $params); $userrepo = repository::get_repository_by_id($repoid, $syscontext); $this->assertFalse($userrepo->can_be_edited_by_user()); // Editing my own instance. $usercontext = context_user::instance($user->id); $repoid = repository::static_function('flickr_public', 'create', 'flickr_public', 0, $usercontext, $params); $userrepo = repository::get_repository_by_id($repoid, $syscontext); $this->assertTrue($userrepo->can_be_edited_by_user()); }
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This script displays one thumbnail of the image in current user's dropbox. * If {@link repository_dropbox::send_thumbnail()} can not display image * the default 64x64 filetype icon is returned * * @package repository_dropbox * @copyright 2012 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require __DIR__ . '/../../config.php'; require_once __DIR__ . '/lib.php'; $repoid = optional_param('repo_id', 0, PARAM_INT); // Repository ID $contextid = optional_param('ctx_id', SYSCONTEXTID, PARAM_INT); // Context ID $source = optional_param('source', '', PARAM_TEXT); // File path in current user's dropbox $thumbnailavailable = isloggedin(); $thumbnailavailable = $thumbnailavailable && $repoid; $thumbnailavailable = $thumbnailavailable && $source; $thumbnailavailable = $thumbnailavailable && ($repo = repository::get_repository_by_id($repoid, $contextid)); $thumbnailavailable = $thumbnailavailable && method_exists($repo, 'send_thumbnail'); if ($thumbnailavailable) { // Try requesting thumbnail and outputting it. // This function exits if thumbnail was retrieved. $repo->send_thumbnail($source); } // Send default icon for the file type. $fileicon = file_extension_icon($source, 64); send_file($CFG->dirroot . '/pix/' . $fileicon . '.png', basename($fileicon) . '.png');
/** * Gets main file in a file area * * if the main file is a link from an external repository * look for the target file in the main file's repository * Note: this functionality only exists in Moodle 2.3+ * * @param stdclass $context * @param string $component 'mod_hotpot' * @param string $filearea 'sourcefile', 'entrytext' or 'exittext' * @param string $filepath despite the name, this is a dir path with leading and trailing "/" * @param string $filename * @param array $file_record * @return stdclass if external file found, false otherwise */ function hotpot_pluginfile_externalfile($context, $component, $filearea, $filepath, $filename, $file_record) { // get file storage $fs = get_file_storage(); // get main file for this $component/$filearea // typically this will be the HotPot quiz file $mainfile = hotpot_pluginfile_mainfile($context, $component, $filearea); // get repository - cautiously :-) if (!$mainfile) { return false; // no main file - shouldn't happen !! } if (!method_exists($mainfile, 'get_repository_id')) { return false; // no file linking in Moodle 2.0 - 2.2 } if (!($repositoryid = $mainfile->get_repository_id())) { return false; // $mainfile is not from an external repository } if (!($repository = repository::get_repository_by_id($repositoryid, $context))) { return false; // $repository is not accessible in this context - shouldn't happen !! } // get repository type switch (true) { case isset($repository->options['type']): $type = $repository->options['type']; break; case isset($repository->instance->typeid): $type = repository::get_type_by_id($repository->instance->typeid); $type = $type->get_typename(); break; default: $type = ''; // shouldn't happen !! } // set paths (within repository) to required file // how we do this depends on the repository $typename // "filesystem" path is in plain text, others are encoded $mainreference = $mainfile->get_reference(); switch ($type) { case 'filesystem': $maindirname = dirname($mainreference); $encodepath = false; break; case 'user': case 'coursefiles': $params = file_storage::unpack_reference($mainreference, true); $maindirname = $params['filepath']; $encodepath = true; break; default: echo 'unknown repository type in hotpot_pluginfile_externalfile(): ' . $type; die; } // remove leading and trailing "/" from dir names $maindirname = trim($maindirname, '/'); $dirname = trim($filepath, '/'); // assume path to target dir is same as path to main dir $path = explode('/', $maindirname); // traverse back up folder hierarchy if necessary $count = count(explode('/', $dirname)); array_splice($path, -$count); // reconstruct expected dir path for source file if ($dirname) { $path[] = $dirname; } $source = $path; $source[] = $filename; $source = implode('/', $source); $path = implode('/', $path); // filepaths in the repository to search for the file $paths = array(); // add to the list of possible paths $paths[$path] = $source; if ($dirname) { $paths[$dirname] = $dirname . '/' . $filename; } if ($maindirname) { $paths[$maindirname] = $maindirname . '/' . $filename; } if ($maindirname && $dirname) { $paths[$maindirname . '/' . $dirname] = $maindirname . '/' . $dirname . '/' . $filename; $paths[$dirname . '/' . $maindirname] = $dirname . '/' . $maindirname . '/' . $filename; } // add leading and trailing "/" to dir names $dirname = $dirname == '' ? '/' : '/' . $dirname . '/'; $maindirname = $maindirname == '' ? '/' : '/' . $maindirname . '/'; // locate $dirname within $maindirname // typically it will be absent or occur just once, // but it could possibly occur several times $search = '/' . preg_quote($dirname, '/') . '/i'; if (preg_match_all($search, $maindirname, $matches, PREG_OFFSET_CAPTURE)) { $i_max = count($matches[0]); for ($i = 0; $i < $i_max; $i++) { list($match, $start) = $matches[0][$i]; $path = substr($maindirname, 0, $start) . $match; $path = trim($path, '/'); // e.g. hp6.2/html_files $paths[$path] = $path . '/' . $filename; } } // setup $params for path encoding, if necessary $params = array(); if ($encodepath) { $listing = $repository->get_listing(); if (isset($listing['list'][0]['path'])) { $params = file_storage::unpack_reference($listing['list'][0]['path'], true); } } foreach ($paths as $path => $source) { if (!hotpot_pluginfile_dirpath_exists($path, $repository, $encodepath, $params)) { continue; } if ($encodepath) { $params['filepath'] = '/' . $path . ($path == '' ? '' : '/'); $params['filename'] = '.'; // "." signifies a directory $path = file_storage::pack_reference($params); } $listing = $repository->get_listing($path); foreach ($listing['list'] as $file) { if (empty($file['source'])) { continue; // a directory - shouldn't happen !! } if ($encodepath) { $file['source'] = file_storage::unpack_reference($file['source']); $file['source'] = trim($file['source']['filepath'], '/') . '/' . $file['source']['filename']; } if ($file['source'] == $source) { if ($encodepath) { $params['filename'] = $filename; $source = file_storage::pack_reference($params); } if ($file = $fs->create_file_from_reference($file_record, $repositoryid, $source)) { return $file; } break; // couldn't create file, so give up and try a different $path } } } // external file not found (or found but not created) return false; }