function lightboxgallery_add_images($stored_file, $context, $cm, $gallery, $resize = 0) { require_once dirname(__FILE__) . '/imageclass.php'; $fs = get_file_storage(); $images = array(); if ($stored_file->get_mimetype() == 'application/zip') { // Unpack. $packer = get_file_packer('application/zip'); $fs->delete_area_files($context->id, 'mod_lightboxgallery', 'unpacktemp', 0); $stored_file->extract_to_storage($packer, $context->id, 'mod_lightboxgallery', 'unpacktemp', 0, '/'); $images = $fs->get_area_files($context->id, 'mod_lightboxgallery', 'unpacktemp', 0); $stored_file->delete(); } else { $images[] = $stored_file; } foreach ($images as $stored_file) { if ($stored_file->is_valid_image()) { $filename = $stored_file->get_filename(); $fileinfo = array('contextid' => $context->id, 'component' => 'mod_lightboxgallery', 'filearea' => 'gallery_images', 'itemid' => 0, 'filepath' => '/', 'filename' => $filename); if (!$fs->get_file($context->id, 'mod_lightboxgallery', 'gallery_images', 0, '/', $filename)) { $stored_file = $fs->create_file_from_storedfile($fileinfo, $stored_file); $image = new lightboxgallery_image($stored_file, $gallery, $cm); if ($resize > 0) { $resizeoptions = lightboxgallery_resize_options(); list($width, $height) = explode('x', $resizeoptions[$resize]); $image->resize_image($width, $height); } $image->set_caption($filename); } } } $fs->delete_area_files($context->id, 'mod_lightboxgallery', 'unpacktemp', 0); }
static function process_attachments($context, $email, $table, $id) { global $CFG, $USER; $base_path = "block_quickmail/{$USER->id}"; $moodle_base = "{$CFG->tempdir}/{$base_path}"; if (!file_exists($moodle_base)) { mkdir($moodle_base, $CFG->directorypermissions, true); } $zipname = $zip = $actual_zip = ''; if (!empty($email->attachment)) { $zipname = "attachment.zip"; $actual_zip = "{$moodle_base}/{$zipname}"; $safe_path = preg_replace('/\\//', "\\/", $CFG->dataroot); $zip = preg_replace("/{$safe_path}\\//", '', $actual_zip); $packer = get_file_packer(); $fs = get_file_storage(); $files = $fs->get_area_files($context->id, 'block_quickmail', 'attachment_' . $table, $id, 'id'); $stored_files = array(); foreach ($files as $file) { if ($file->is_directory() and $file->get_filename() == '.') { continue; } $stored_files[$file->get_filepath() . $file->get_filename()] = $file; } $packer->archive_to_pathname($stored_files, $actual_zip); } return array($zipname, $zip, $actual_zip); }
/** * Export one book as IMSCP package * * @param stdClass $book book instance * @param context_module $context * @return bool|stored_file */ function booktool_exportimscp_build_package($book, $context) { global $DB; $fs = get_file_storage(); if ($packagefile = $fs->get_file($context->id, 'booktool_exportimscp', 'package', $book->revision, '/', 'imscp.zip')) { return $packagefile; } // fix structure and test if chapters present if (!book_preload_chapters($book)) { print_error('nochapters', 'booktool_exportimscp'); } // prepare temp area with package contents booktool_exportimscp_prepare_files($book, $context); $packer = get_file_packer('application/zip'); $areafiles = $fs->get_area_files($context->id, 'booktool_exportimscp', 'temp', $book->revision, "sortorder, itemid, filepath, filename", false); $files = array(); foreach ($areafiles as $file) { $path = $file->get_filepath() . $file->get_filename(); $path = ltrim($path, '/'); $files[$path] = $file; } unset($areafiles); $packagefile = $packer->archive_to_storage($files, $context->id, 'booktool_exportimscp', 'package', $book->revision, '/', 'imscp.zip'); // drop temp area $fs->delete_area_files($context->id, 'booktool_exportimscp', 'temp', $book->revision); // delete older versions $sql = "SELECT DISTINCT itemid\n FROM {files}\n WHERE contextid = :contextid AND component = 'booktool_exportimscp' AND itemid < :revision"; $params = array('contextid' => $context->id, 'revision' => $book->revision); $revisions = $DB->get_records_sql($sql, $params); foreach ($revisions as $rev => $unused) { $fs->delete_area_files($context->id, 'booktool_exportimscp', 'temp', $rev); $fs->delete_area_files($context->id, 'booktool_exportimscp', 'package', $rev); } return $packagefile; }
/** * Backup a course and return its backup ID. * * @param int $courseid The course ID. * @param int $userid The user doing the backup. * @return string */ protected function backup_course($courseid, $userid = 2) { global $CFG; $packer = get_file_packer('application/vnd.moodle.backup'); $bc = new backup_controller(backup::TYPE_1COURSE, $courseid, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $userid); $bc->execute_plan(); $results = $bc->get_results(); $results['backup_destination']->extract_to_pathname($packer, "{$CFG->tempdir}/backup/core_course_testcase"); $bc->destroy(); unset($bc); return 'core_course_testcase'; }
public function test_archive_with_both_options() { global $CFG; $this->resetAfterTest(); // Get backup packer. $packer = get_file_packer('application/vnd.moodle.backup'); require_once $CFG->dirroot . '/lib/filestorage/tgz_packer.php'; if (!tgz_packer::has_required_extension()) { $this->markTestSkipped('zlib not available'); return; } // Set up basic archive contents. $files = array('1.txt' => array('frog')); // Create 2 archives (each with one file in) in default mode. $CFG->enabletgzbackups = false; $filefalse = $CFG->tempdir . '/false.mbz'; $this->assertNotEmpty($packer->archive_to_pathname($files, $filefalse)); $context = context_system::instance(); $this->assertNotEmpty($storagefalse = $packer->archive_to_storage($files, $context->id, 'phpunit', 'data', 0, '/', 'false.mbz')); // Create 2 archives in tgz mode. $CFG->enabletgzbackups = true; $filetrue = $CFG->tempdir . '/true.mbz'; $this->assertNotEmpty($packer->archive_to_pathname($files, $filetrue)); $context = context_system::instance(); $this->assertNotEmpty($storagetrue = $packer->archive_to_storage($files, $context->id, 'phpunit', 'data', 0, '/', 'false.mbz')); // Check the sizes are different (indicating different formats). $this->assertNotEquals(filesize($filefalse), filesize($filetrue)); $this->assertNotEquals($storagefalse->get_filesize(), $storagetrue->get_filesize()); // Extract files into storage and into filesystem from both formats. // (Note: the setting does not matter, but set to false just to check.) $CFG->enabletgzbackups = false; // Extract to path (zip). $packer->extract_to_pathname($filefalse, $CFG->tempdir); $onefile = $CFG->tempdir . '/1.txt'; $this->assertEquals('frog', file_get_contents($onefile)); unlink($onefile); // Extract to path (tgz). $packer->extract_to_pathname($filetrue, $CFG->tempdir); $onefile = $CFG->tempdir . '/1.txt'; $this->assertEquals('frog', file_get_contents($onefile)); unlink($onefile); // Extract to storage (zip). $packer->extract_to_storage($storagefalse, $context->id, 'phpunit', 'data', 1, '/'); $fs = get_file_storage(); $out = $fs->get_file($context->id, 'phpunit', 'data', 1, '/', '1.txt'); $this->assertNotEmpty($out); $this->assertEquals('frog', $out->get_content()); // Extract to storage (tgz). $packer->extract_to_storage($storagetrue, $context->id, 'phpunit', 'data', 2, '/'); $out = $fs->get_file($context->id, 'phpunit', 'data', 2, '/', '1.txt'); $this->assertNotEmpty($out); $this->assertEquals('frog', $out->get_content()); }
static function zip_attachments($context, $table, $id) { global $CFG, $USER; $base_path = "block_quickmail/{$USER->id}"; $moodle_base = "{$CFG->tempdir}/{$base_path}"; if (!file_exists($moodle_base)) { mkdir($moodle_base, $CFG->directorypermissions, true); } $zipname = "attachment.zip"; $actual_zip = "{$moodle_base}/{$zipname}"; $fs = get_file_storage(); $packer = get_file_packer(); $files = $fs->get_area_files($context->id, 'block_quickmail', 'attachment_' . $table, $id, 'id'); $stored_files = array(); foreach ($files as $file) { if ($file->is_directory() and $file->get_filename() == '.') { continue; } $stored_files[$file->get_filepath() . $file->get_filename()] = $file; } $packer->archive_to_pathname($stored_files, $actual_zip); return $actual_zip; }
/** * Test that triggering a course_restored event works as expected. */ public function test_course_restored_event() { global $CFG; // Get the necessary files to perform backup and restore. require_once $CFG->dirroot . '/backup/util/includes/backup_includes.php'; require_once $CFG->dirroot . '/backup/util/includes/restore_includes.php'; $this->resetAfterTest(); // Set to admin user. $this->setAdminUser(); // The user id is going to be 2 since we are the admin user. $userid = 2; // Create a course. $course = $this->getDataGenerator()->create_course(); // Create backup file and save it to the backup location. $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $userid); $bc->execute_plan(); $results = $bc->get_results(); $file = $results['backup_destination']; $fp = get_file_packer('application/vnd.moodle.backup'); $filepath = $CFG->dataroot . '/temp/backup/test-restore-course-event'; $file->extract_to_pathname($fp, $filepath); $bc->destroy(); unset($bc); // Now we want to catch the restore course event. $sink = $this->redirectEvents(); // Now restore the course to trigger the event. $rc = new restore_controller('test-restore-course-event', $course->id, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $userid, backup::TARGET_NEW_COURSE); $rc->execute_precheck(); $rc->execute_plan(); // Capture the event. $events = $sink->get_events(); $sink->close(); // Validate the event. $event = array_pop($events); $this->assertInstanceOf('\\core\\event\\course_restored', $event); $this->assertEquals('course', $event->objecttable); $this->assertEquals($rc->get_courseid(), $event->objectid); $this->assertEquals(context_course::instance($rc->get_courseid())->id, $event->contextid); $this->assertEquals('course_restored', $event->get_legacy_eventname()); $legacydata = (object) array('courseid' => $rc->get_courseid(), 'userid' => $rc->get_userid(), 'type' => $rc->get_type(), 'target' => $rc->get_target(), 'mode' => $rc->get_mode(), 'operation' => $rc->get_operation(), 'samesite' => $rc->is_samesite()); $url = new moodle_url('/course/view.php', array('id' => $event->objectid)); $this->assertEquals($url, $event->get_url()); $this->assertEventLegacyData($legacydata, $event); $this->assertEventContextNotUsed($event); // Destroy the resource controller since we are done using it. $rc->destroy(); unset($rc); }
/** * Process the attached file(s). If multiple files, create a zip file. */ public static function process_attachments($context, $email, $table, $id) { global $CFG, $USER; $base_path = "block_clampmail/{$USER->id}"; $moodle_base = "{$CFG->tempdir}/{$base_path}"; if (!file_exists($moodle_base)) { mkdir($moodle_base, $CFG->directorypermissions, true); } $filename = $file = $actual_file = ''; if (!empty($email->attachment)) { $fs = get_file_storage(); $stored_files = array(); $safe_path = preg_replace('/\\//', "\\/", $CFG->dataroot); $base_file_path = preg_replace("/{$safe_path}\\//", '', $moodle_base); $files = $fs->get_area_files($context->id, 'block_clampmail', 'attachment_' . $table, $id, 'id'); // Cycle through files. foreach ($files as $item) { if ($item->is_directory() && $item->get_filename() == '.') { continue; } $stored_files[$item->get_filepath() . $item->get_filename()] = $item; } // Create a zip archive if more than one file. if (count($stored_files) == 1) { $obj = current($stored_files); $filename = $obj->get_filename(); $file = $base_file_path . '/' . $filename; $actual_file = $moodle_base . '/' . $filename; $obj->copy_content_to($actual_file); } else { $filename = 'attachment.zip'; $file = $base_file_path . '/' . $filename; $actual_file = $moodle_base . '/' . $filename; $packer = get_file_packer(); $packer->archive_to_pathname($stored_files, $actual_file); } } return array($filename, $file, $actual_file); }
protected function define_execution() { // Get basepath $basepath = $this->get_basepath(); // Get the list of files in directory $filestemp = get_directory_list($basepath, '', false, true, true); $files = array(); foreach ($filestemp as $file) { // Add zip paths and fs paths to all them $files[$file] = $basepath . '/' . $file; } // Calculate the zip fullpath (in OS temp area it's always backup.mbz) $zipfile = $basepath . '/backup.imscc'; // Get the zip packer $zippacker = get_file_packer('application/zip'); // Zip files $zippacker->archive_to_pathname($files, $zipfile); }
function validation($data, $files) { $errors = parent::validation($data, $files); $type = $data['scormtype']; if ($type === SCORM_TYPE_LOCAL) { if (!empty($data['update'])) { //ok, not required } else { if (empty($files['packagefile'])) { $errors['packagefile'] = get_string('required'); } else { $packer = get_file_packer('application/zip'); $filelist = $packer->list_files($files['packagefile']); if (!is_array($filelist)) { $errors['packagefile'] = 'Incorrect file package - not an archive'; //TODO: localise } else { $manifestpresent = false; $aiccfound = false; foreach ($filelist as $info) { if ($info->pathname == 'imsmanifest.xml') { $manifestpresent = true; break; } if (preg_match('/\\.cst$/', $info->pathname)) { $aiccfound = true; break; } } if (!$manifestpresent and !$aiccfound) { $errors['packagefile'] = 'Incorrect file package - missing imsmanifest.xml or AICC structure'; //TODO: localise } } } } } else { if ($type === SCORM_TYPE_EXTERNAL) { $reference = $data['packageurl']; if (!preg_match('/(http:\\/\\/|https:\\/\\/|www).*\\/imsmanifest.xml$/i', $reference)) { $errors['packageurl'] = get_string('required'); // TODO: improve help } } else { if ($type === 'packageurl') { $reference = $data['reference']; if (!preg_match('/(http:\\/\\/|https:\\/\\/|www).*(\\.zip|\\.pif)$/i', $reference)) { $errors['packageurl'] = get_string('required'); // TODO: improve help } } else { if ($type === SCORM_TYPE_IMSREPOSITORY) { $reference = $data['packageurl']; if (stripos($reference, '#') !== 0) { $errors['packageurl'] = get_string('required'); } } } } } return $errors; }
/** * Extracts scrom package, sets up all variables. * Called whenever scorm changes * @param object $scorm instance - fields are updated and changes saved into database * @param bool $full force full update if true * @return void */ function scorm_parse($scorm, $full) { global $CFG, $DB; $cfg_scorm = get_config('scorm'); if (!isset($scorm->cmid)) { $cm = get_coursemodule_from_instance('scorm', $scorm->id); $scorm->cmid = $cm->id; } $context = get_context_instance(CONTEXT_MODULE, $scorm->cmid); $newhash = $scorm->sha1hash; if ($scorm->scormtype === SCORM_TYPE_LOCAL or $scorm->scormtype === SCORM_TYPE_LOCALSYNC) { $fs = get_file_storage(); $packagefile = false; if ($scorm->scormtype === SCORM_TYPE_LOCAL) { if ($packagefile = $fs->get_file($context->id, 'mod_scorm', 'package', 0, '/', $scorm->reference)) { $newhash = $packagefile->get_contenthash(); } else { $newhash = null; } } else { if (!$cfg_scorm->allowtypelocalsync) { // sorry - localsync disabled return; } if ($scorm->reference !== '' and (!$full or $scorm->sha1hash !== sha1($scorm->reference))) { $fs->delete_area_files($context->id, 'mod_scorm', 'package'); $file_record = array('contextid'=>$context->id, 'component'=>'mod_scorm', 'filearea'=>'package', 'itemid'=>0, 'filepath'=>'/'); if ($packagefile = $fs->create_file_from_url($file_record, $scorm->reference, array('calctimeout' => true))) { $newhash = sha1($scorm->reference); } else { $newhash = null; } } } if ($packagefile) { if (!$full and $packagefile and $scorm->sha1hash === $newhash) { if (strpos($scorm->version, 'SCORM') !== false) { if ($fs->get_file($context->id, 'mod_scorm', 'content', 0, '/', 'imsmanifest.xml')) { // no need to update return; } } else if (strpos($scorm->version, 'AICC') !== false) { // TODO: add more sanity checks - something really exists in scorm_content area return; } } // now extract files $fs->delete_area_files($context->id, 'mod_scorm', 'content'); $packer = get_file_packer('application/zip'); $packagefile->extract_to_storage($packer, $context->id, 'mod_scorm', 'content', 0, '/'); } else if (!$full) { return; } if ($manifest = $fs->get_file($context->id, 'mod_scorm', 'content', 0, '/', 'imsmanifest.xml')) { require_once("$CFG->dirroot/mod/scorm/datamodels/scormlib.php"); // SCORM if (!scorm_parse_scorm($scorm, $manifest)) { $scorm->version = 'ERROR'; } } else { require_once("$CFG->dirroot/mod/scorm/datamodels/aicclib.php"); // AICC if (!scorm_parse_aicc($scorm)) { $scorm->version = 'ERROR'; } $scorm->version = 'AICC'; } } else if ($scorm->scormtype === SCORM_TYPE_EXTERNAL and $cfg_scorm->allowtypeexternal) { if (!$full and $scorm->sha1hash === sha1($scorm->reference)) { return; } require_once("$CFG->dirroot/mod/scorm/datamodels/scormlib.php"); // SCORM only, AICC can not be external if (!scorm_parse_scorm($scorm, $scorm->reference)) { $scorm->version = 'ERROR'; } $newhash = sha1($scorm->reference); } else if ($scorm->scormtype === SCORM_TYPE_IMSREPOSITORY and !empty($CFG->repositoryactivate) and $cfg_scorm->allowtypeimsrepository) { if (!$full and $scorm->sha1hash === sha1($scorm->reference)) { return; } require_once("$CFG->dirroot/mod/scorm/datamodels/scormlib.php"); if (!scorm_parse_scorm($scorm, $CFG->repository.substr($scorm->reference, 1).'/imsmanifest.xml')) { $scorm->version = 'ERROR'; } $newhash = sha1($scorm->reference); } else if ($scorm->scormtype === SCORM_TYPE_AICCURL and $cfg_scorm->allowtypeexternalaicc) { require_once("$CFG->dirroot/mod/scorm/datamodels/aicclib.php"); // AICC if (!scorm_parse_aicc($scorm)) { $scorm->version = 'ERROR'; } $scorm->version = 'AICC'; } else { // sorry, disabled type return; } $scorm->revision++; $scorm->sha1hash = $newhash; $DB->update_record('scorm', $scorm); }
protected function define_execution() { // Get basepath $basepath = $this->get_basepath(); // Get the list of files in directory $filestemp = get_directory_list($basepath, '', false, true, true); $files = array(); foreach ($filestemp as $file) { // Add zip paths and fs paths to all them $files[$file] = $basepath . '/' . $file; } // Add the log file if exists $logfilepath = $basepath . '.log'; if (file_exists($logfilepath)) { $files['moodle_backup.log'] = $logfilepath; } // Calculate the zip fullpath (in OS temp area it's always backup.mbz) $zipfile = $basepath . '/backup.mbz'; // Get the zip packer $zippacker = get_file_packer('application/vnd.moodle.backup'); // Track overall progress for the 2 long-running steps (archive to // pathname, get backup information). $reporter = $this->task->get_progress(); $reporter->start_progress('backup_zip_contents', 2); // Zip files $result = $zippacker->archive_to_pathname($files, $zipfile, true, $this); // If any sub-progress happened, end it. if ($this->startedprogress) { $this->task->get_progress()->end_progress(); $this->startedprogress = false; } else { // No progress was reported, manually move it on to the next overall task. $reporter->progress(1); } // Something went wrong. if ($result === false) { @unlink($zipfile); throw new backup_step_exception('error_zip_packing', '', 'An error was encountered while trying to generate backup zip'); } // Read to make sure it is a valid backup. Refer MDL-37877 . Delete it, if found not to be valid. try { backup_general_helper::get_backup_information_from_mbz($zipfile, $this); } catch (backup_helper_exception $e) { @unlink($zipfile); throw new backup_step_exception('error_zip_packing', '', $e->debuginfo); } // If any sub-progress happened, end it. if ($this->startedprogress) { $this->task->get_progress()->end_progress(); $this->startedprogress = false; } else { $reporter->progress(2); } $reporter->end_progress(); }
$data = new stdClass; $data->id = $cm->id; $data->pageid = $pageid; $mform = new lesson_importppt_form(); $mform->set_data($data); if ($data = $mform->get_data()) { $manager = lesson_page_type_manager::get($lesson); if (!$filename = $mform->get_new_filename('pptzip')) { print_error('invalidfile', 'lesson'); } if (!$package = $mform->save_stored_file('pptzip', $context->id, 'mod_lesson', 'ppt_imports', $lesson->id, '/', $filename, true)) { print_error('unabletosavefile', 'lesson'); } // extract package content $packer = get_file_packer('application/zip'); $package->extract_to_storage($packer, $context->id, 'mod_lesson', 'imported_files', $lesson->id, '/'); $fs = get_file_storage(); if ($files = $fs->get_area_files($context->id, 'mod_lesson', 'imported_files', $lesson->id)) { $pages = array(); foreach ($files as $key=>$file) { if ($file->get_mimetype() != 'text/html') { continue; } $filenameinfo = pathinfo($file->get_filepath().$file->get_filename()); $page = new stdClass; $page->title = ''; $page->contents = array();
/** * Generates list of zip files in array. * * @param int $batch id of batch * @return array|bool False on no files to add to zip, array on success * @uses $CFG, $DB */ function report_ncccscensus_generate_bulk_zip($batch) { global $DB, $USER; // Check if last report. $left = $DB->count_records('report_ncccscensus', array('batchid' => $batch, 'status' => 0)); if ($left !== 0) { return false; } $files = report_ncccscensus_get_zip_files($batch); if (!is_array($files)) { return false; } $date = usergetdate(time(), get_user_timezone()); $filename = date('MdY_Hi', mktime($date['hours'], $date['minutes'], 0, $date['mon'], $date['mday'], $date['year'])); $filename = $filename . '-' . $batch . '.zip'; $fs = get_file_storage(); // Check to see if file exists. $contextid = context_system::instance()->id; $file = $fs->get_file($contextid, 'report_ncccscensus', 'archive', $batch, '/report_ncccscensus/', $filename); if (!$file) { // Prepare file record object. $fileinfo = array('contextid' => context_system::instance()->id, 'component' => 'report_ncccscensus', 'filearea' => 'archive', 'itemid' => $batch, 'filepath' => '/report_ncccscensus/', 'filename' => $filename); $file = $fs->create_file_from_string($fileinfo, ''); } $parentpath = $file->get_parent_directory()->get_filepath(); $filepath = explode('/', trim($file->get_filepath(), '/')); $filepath = array_pop($filepath); // Generate zip. $zipper = get_file_packer('application/zip'); $record = $DB->get_record('report_ncccscensus_batch', array('id' => $batch)); $contextid = context_system::instance()->id; $path = 'report_ncccscensus'; $newfile = $zipper->archive_to_storage($files, $contextid, $path, 'archive', $batch, $parentpath, $filename, $USER->id); if ($newfile) { // Mark batch as complete. $record->zipfile = $filename; } $record->status = 1; $DB->update_record('report_ncccscensus_batch', $record); $info = array(); // Delete pdf files. foreach ($files as $filename => $fullfilename) { @unlink($fullfilename); $info = pathinfo($fullfilename); } if (!empty($info['dirname'])) { @rmdir($info['dirname']); } }
function validation($data, $files) { global $CFG; $errors = parent::validation($data, $files); $type = $data['scormtype']; if ($type === SCORM_TYPE_LOCAL) { if (!empty($data['update'])) { //ok, not required } else if (empty($data['packagefile'])) { $errors['packagefile'] = get_string('required'); } else { $files = $this->get_draft_files('packagefile'); if (count($files)<1) { $errors['packagefile'] = get_string('required'); return $errors; } $file = reset($files); $filename = $CFG->tempdir.'/scormimport/scrom_'.time(); make_temp_directory('scormimport'); $file->copy_content_to($filename); $packer = get_file_packer('application/zip'); $filelist = $packer->list_files($filename); if (!is_array($filelist)) { $errors['packagefile'] = 'Incorrect file package - not an archive'; //TODO: localise } else { $manifestpresent = false; $aiccfound = false; foreach ($filelist as $info) { if ($info->pathname == 'imsmanifest.xml') { $manifestpresent = true; break; } if (preg_match('/\.cst$/', $info->pathname)) { $aiccfound = true; break; } } if (!$manifestpresent and !$aiccfound) { $errors['packagefile'] = 'Incorrect file package - missing imsmanifest.xml or AICC structure'; //TODO: localise } } unlink($filename); } } 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_IMSREPOSITORY) { $reference = $data['packageurl']; if (stripos($reference, '#') !== 0) { $errors['packageurl'] = get_string('invalidurl', 'scorm'); } } 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; }
protected function extract_file_to_dir() { global $CFG, $USER; $this->filepath = restore_controller::get_tempdir_name($this->contextid, $USER->id); $fb = get_file_packer(); return $fb->extract_to_pathname("{$CFG->tempdir}/backup/" . $this->filename, "{$CFG->tempdir}/backup/{$this->filepath}/"); }
/** * Selects appropriate packer for existing archive depending on file contents. * * @param string|stored_file $archivefile full pathname of zip file or stored_file instance * @return file_packer Suitable packer */ protected function get_packer_for_read_operation($archivefile) { global $CFG; require_once $CFG->dirroot . '/lib/filestorage/tgz_packer.php'; if (tgz_packer::is_tgz_file($archivefile)) { return get_file_packer('application/x-gzip'); } else { return get_file_packer('application/zip'); } }
/** * Check that a Zip file contains a valid SCORM package * * @param $file stored_file a Zip file. * @return array empty if no issue is found. Array of error message otherwise */ function scorm_validate_package($file) { $packer = get_file_packer('application/zip'); $errors = array(); if ($file->is_external_file()) { // Get zip file so we can check it is correct. $file->import_external_file_contents(); } $filelist = $file->list_files($packer); if (!is_array($filelist)) { $errors['packagefile'] = get_string('badarchive', 'scorm'); } else { $aiccfound = false; $badmanifestpresent = false; foreach ($filelist as $info) { if ($info->pathname == 'imsmanifest.xml') { return array(); } else if (strpos($info->pathname, 'imsmanifest.xml') !== false) { // This package has an imsmanifest file inside a folder of the package. $badmanifestpresent = true; } if (preg_match('/\.cst$/', $info->pathname)) { return array(); } } if (!$aiccfound) { if ($badmanifestpresent) { $errors['packagefile'] = get_string('badimsmanifestlocation', 'scorm'); } else { $errors['packagefile'] = get_string('nomanifest', 'scorm'); } } } return $errors; }
public function execute() { global $CFG, $DB, $USER; require_once $CFG->dirroot . "/backup/util/includes/backup_includes.php"; require_once $CFG->dirroot . "/backup/util/includes/restore_includes.php"; $arguments = $this->arguments; $options = $this->expandedOptions; if (empty($CFG->tempdir)) { $CFG->tempdir = $CFG->dataroot . DIRECTORY_SEPARATOR . 'temp'; } // Check if category is OK. if (!$options['existing']) { $category = $DB->get_record('course_categories', array('id' => $this->arguments[1]), '*', MUST_EXIST); } else { $course = $DB->get_record('course', array('id' => $this->arguments[1]), '*', MUST_EXIST); $category = $DB->get_record('course_categories', array('id' => $course->category), '*', MUST_EXIST); } if (!$options['directory']) { if ($arguments[0][0] != '/') { $arguments[0] = $this->cwd . DIRECTORY_SEPARATOR . $arguments[0]; } if (!file_exists($arguments[0])) { cli_error("Backup file '" . $arguments[0] . "' does not exist."); } if (!is_readable($arguments[0])) { cli_error("Backup file '" . $arguments[0] . "' is not readable."); } } else { $path = $CFG->tempdir . DIRECTORY_SEPARATOR . "backup" . DIRECTORY_SEPARATOR . $arguments[0]; if (!file_exists($path) || !is_dir($path) || !is_readable($path)) { cli_error("Directory '{$path}' does not exist, not a directory or not readable."); } } if (!$options['directory']) { //unzip into $CFG->tempdir / "backup" / "auto_restore_" . $split[1]; $backupdir = "moosh_restore_" . uniqid(); $path = $CFG->tempdir . DIRECTORY_SEPARATOR . "backup" . DIRECTORY_SEPARATOR . $backupdir; if ($this->verbose) { echo "Extracting Moode backup file to: '" . $path . "'\n"; } /** @var $fp file_packer */ $fp = get_file_packer('application/vnd.moodle.backup'); $fp->extract_to_pathname($arguments[0], $path); } else { $backupdir = $arguments[0]; } //extract original full & short names $xmlfile = $path . DIRECTORY_SEPARATOR . "course" . DIRECTORY_SEPARATOR . "course.xml"; // Different XML file in Moodle 1.9 backup if (!file_exists($xmlfile)) { $xmlfile = $path . DIRECTORY_SEPARATOR . "moodle.xml"; } $xml = simplexml_load_file($xmlfile); $fullname = $xml->xpath('/course/fullname'); if (!$fullname) { $fullname = $xml->xpath('/MOODLE_BACKUP/COURSE/HEADER/FULLNAME'); } $shortname = $xml->xpath('/course/shortname'); if (!$shortname) { $shortname = $xml->xpath('/MOODLE_BACKUP/COURSE/HEADER/SHORTNAME'); } $fullname = (string) $fullname[0]; $shortname = (string) $shortname[0]; if (!$shortname) { cli_error('No shortname in the backup file.'); } if (!$fullname) { $fullname = $shortname; } // Get unique shortname if creating new course. if (!$options['existing'] && $DB->get_record('course', array('category' => $category->id, 'shortname' => $shortname))) { $matches = NULL; preg_match('/(.*)_(\\d+)$/', $shortname, $matches); if ($matches) { $base = $matches[1]; $number = $matches[2]; } else { $base = $shortname; $number = 1; } $shortname = $base . '_' . $number; while ($DB->get_record('course', array('category' => $category->id, 'shortname' => $shortname))) { $number++; $shortname = $base . '_' . $number; } } if ($options['existing']) { $courseid = $arguments[1]; $rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $USER->id, backup::TARGET_CURRENT_ADDING); } else { $courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id); $rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $USER->id, backup::TARGET_NEW_COURSE); } echo "Restoring (new course id,shortname,destination category): {$courseid},{$shortname}," . $category->id . "\n"; if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) { $rc->convert(); } $plan = $rc->get_plan(); $tasks = $plan->get_tasks(); foreach ($tasks as &$task) { $setting = $task->get_setting('enrol_migratetomanual'); $setting->set_value('1'); } $rc->execute_precheck(); $rc->execute_plan(); $rc->destroy(); echo "New course ID for '{$shortname}': {$courseid} in {$category->id}\n"; }
/** * Tests the progress reporting. */ public function test_file_progress() { global $CFG; // Set up. $this->resetAfterTest(true); $packer = get_file_packer('application/zip'); $archive = "{$CFG->tempdir}/archive.zip"; $context = context_system::instance(); // Archive to pathname. $this->progress = array(); $result = $packer->archive_to_pathname($this->files, $archive, true, $this); $this->assertTrue($result); // Should send progress at least once per file. $this->assertTrue(count($this->progress) >= count($this->files)); // Each progress will be indeterminate. $this->assertEquals(array(file_progress::INDETERMINATE, file_progress::INDETERMINATE), $this->progress[0]); // Archive to pathname using entire folder and subfolder instead of file list. unlink($archive); $folder = make_temp_directory('zip_packer_progress'); file_put_contents($folder . '/test1.txt', 'hello'); $subfolder = $folder . '/sub'; check_dir_exists($subfolder); file_put_contents($subfolder . '/test2.txt', 'world'); file_put_contents($subfolder . '/test3.txt', 'and'); file_put_contents($subfolder . '/test4.txt', 'other'); file_put_contents($subfolder . '/test5.txt', 'worlds'); $this->progress = array(); $result = $packer->archive_to_pathname(array('' => $folder), $archive, true, $this); $this->assertTrue($result); // Should send progress at least once per file. $this->assertTrue(count($this->progress) >= 5); // Archive to storage. $this->progress = array(); $archivefile = $packer->archive_to_storage($this->files, $context->id, 'phpunit', 'test', 0, '/', 'archive.zip', null, true, $this); $this->assertInstanceOf('stored_file', $archivefile); $this->assertTrue(count($this->progress) >= count($this->files)); $this->assertEquals(array(file_progress::INDETERMINATE, file_progress::INDETERMINATE), $this->progress[0]); // Extract to pathname. $this->progress = array(); $target = "{$CFG->tempdir}/test/"; check_dir_exists($target); $result = $packer->extract_to_pathname($archive, $target, null, $this); remove_dir($target); $this->assertEquals(count($this->files), count($result)); $this->assertTrue(count($this->progress) >= count($this->files)); $this->check_progress_toward_max(); // Extract to storage (from storage). $this->progress = array(); $result = $packer->extract_to_storage($archivefile, $context->id, 'phpunit', 'target', 0, '/', null, $this); $this->assertEquals(count($this->files), count($result)); $this->assertTrue(count($this->progress) >= count($this->files)); $this->check_progress_toward_max(); // Extract to storage (from path). $this->progress = array(); $result = $packer->extract_to_storage($archive, $context->id, 'phpunit', 'target', 0, '/', null, $this); $this->assertEquals(count($this->files), count($result)); $this->assertTrue(count($this->progress) >= count($this->files)); $this->check_progress_toward_max(); // Wipe created disk file. unlink($archive); }
/** * Zip an array of files/dirs to a destination zip file * Both parameters must be FULL paths to the files/dirs * * @global object * @param array $originalfiles Files to zip * @param string $destination The destination path * @return bool Outcome */ function zip_files ($originalfiles, $destination) { global $CFG; //Extract everything from destination $path_parts = pathinfo(cleardoubleslashes($destination)); $destpath = $path_parts["dirname"]; //The path of the zip file $destfilename = $path_parts["basename"]; //The name of the zip file $extension = $path_parts["extension"]; //The extension of the file //If no file, error if (empty($destfilename)) { return false; } //If no extension, add it if (empty($extension)) { $extension = 'zip'; $destfilename = $destfilename.'.'.$extension; } //Check destination path exists if (!is_dir($destpath)) { return false; } //Check destination path is writable. TODO!! //Clean destination filename $destfilename = clean_filename($destfilename); //Now check and prepare every file $files = array(); $origpath = NULL; foreach ($originalfiles as $file) { //Iterate over each file //Check for every file $tempfile = cleardoubleslashes($file); // no doubleslashes! //Calculate the base path for all files if it isn't set if ($origpath === NULL) { $origpath = rtrim(cleardoubleslashes(dirname($tempfile)), "/"); } //See if the file is readable if (!is_readable($tempfile)) { //Is readable continue; } //See if the file/dir is in the same directory than the rest if (rtrim(cleardoubleslashes(dirname($tempfile)), "/") != $origpath) { continue; } //Add the file to the array $files[] = $tempfile; } $zipfiles = array(); $start = strlen($origpath)+1; foreach($files as $file) { $zipfiles[substr($file, $start)] = $file; } $packer = get_file_packer('application/zip'); return $packer->archive_to_pathname($zipfiles, $destpath . '/' . $destfilename); }
public function __construct($course, $cm, $module, $filepath) { global $USER; if (is_file($filepath)) { $fp = get_file_packer(); if ($fp->extract_to_pathname($filepath, $filepath.'_extracted')) { fulldelete($filepath); } $filepath .= '_extracted'; } parent::__construct($course, $cm, $module, $filepath); }
/** * Update imscp instance. * @param object $data * @param object $mform * @return bool true */ function imscp_update_instance($data, $mform) { global $CFG, $DB; require_once("$CFG->dirroot/mod/imscp/locallib.php"); $cmid = $data->coursemodule; $data->timemodified = time(); $data->id = $data->instance; $data->structure = null; // better reparse structure after each update $DB->update_record('imscp', $data); $context = get_context_instance(CONTEXT_MODULE, $cmid); $imscp = $DB->get_record('imscp', array('id'=>$data->id), '*', MUST_EXIST); if ($filename = $mform->get_new_filename('package')) { $fs = get_file_storage(); $imscp->revision++; $DB->update_record('imscp', $imscp); // get a list of existing packages before adding new package if ($imscp->keepold > -1) { $packages = $fs->get_area_files($context->id, 'mod_imscp', 'backup', false, "itemid ASC", false); } else { $packages = array(); } $package = $mform->save_stored_file('package', $context->id, 'mod_imscp', 'backup', $imscp->revision, '/', $filename); // purge all extracted content $fs->delete_area_files($context->id, 'mod_imscp', 'content'); // extract package content if ($package) { $packer = get_file_packer('application/zip'); $package->extract_to_storage($packer, $context->id, 'mod_imscp', 'content', $imscp->revision, '/'); } // cleanup old package files, keep current + keepold while ($packages and (count($packages) > $imscp->keepold)) { $package = array_shift($packages); $fs->delete_area_files($context->id, 'mod_imscp', 'backup', $package->get_itemid()); } } $structure = imscp_parse_structure($imscp, $context); $imscp->structure = is_array($structure) ? serialize($structure) : null; $DB->update_record('imscp', $imscp); return true; }
/** * Duplicate a course * * @param int $courseid * @param string $fullname Duplicated course fullname * @param string $shortname Duplicated course shortname * @param int $categoryid Duplicated course parent category id * @param int $visible Duplicated course availability * @param array $options List of backup options * @return array New course info * @since Moodle 2.3 */ public static function duplicate_course($courseid, $fullname, $shortname, $categoryid, $visible = 1, $options = array()) { global $CFG, $USER, $DB; require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); // Parameter validation. $params = self::validate_parameters( self::duplicate_course_parameters(), array( 'courseid' => $courseid, 'fullname' => $fullname, 'shortname' => $shortname, 'categoryid' => $categoryid, 'visible' => $visible, 'options' => $options ) ); // Context validation. if (! ($course = $DB->get_record('course', array('id'=>$params['courseid'])))) { throw new moodle_exception('invalidcourseid', 'error'); } // Category where duplicated course is going to be created. $categorycontext = context_coursecat::instance($params['categoryid']); self::validate_context($categorycontext); // Course to be duplicated. $coursecontext = context_course::instance($course->id); self::validate_context($coursecontext); $backupdefaults = array( 'activities' => 1, 'blocks' => 1, 'filters' => 1, 'users' => 0, 'role_assignments' => 0, 'comments' => 0, 'userscompletion' => 0, 'logs' => 0, 'grade_histories' => 0 ); $backupsettings = array(); // Check for backup and restore options. if (!empty($params['options'])) { foreach ($params['options'] as $option) { // Strict check for a correct value (allways 1 or 0, true or false). $value = clean_param($option['value'], PARAM_INT); if ($value !== 0 and $value !== 1) { throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']); } if (!isset($backupdefaults[$option['name']])) { throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']); } $backupsettings[$option['name']] = $value; } } // Capability checking. // The backup controller check for this currently, this may be redundant. require_capability('moodle/course:create', $categorycontext); require_capability('moodle/restore:restorecourse', $categorycontext); require_capability('moodle/backup:backupcourse', $coursecontext); if (!empty($backupsettings['users'])) { require_capability('moodle/backup:userinfo', $coursecontext); require_capability('moodle/restore:userinfo', $categorycontext); } // Check if the shortname is used. if ($foundcourses = $DB->get_records('course', array('shortname'=>$shortname))) { foreach ($foundcourses as $foundcourse) { $foundcoursenames[] = $foundcourse->fullname; } $foundcoursenamestring = implode(',', $foundcoursenames); throw new moodle_exception('shortnametaken', '', '', $foundcoursenamestring); } // Backup the course. $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id); foreach ($backupsettings as $name => $value) { $bc->get_plan()->get_setting($name)->set_value($value); } $backupid = $bc->get_backupid(); $backupbasepath = $bc->get_plan()->get_basepath(); $bc->execute_plan(); $results = $bc->get_results(); $file = $results['backup_destination']; $bc->destroy(); // Restore the backup immediately. // Check if we need to unzip the file because the backup temp dir does not contains backup files. if (!file_exists($backupbasepath . "/moodle_backup.xml")) { $file->extract_to_pathname(get_file_packer(), $backupbasepath); } // Create new course. $newcourseid = restore_dbops::create_new_course($params['fullname'], $params['shortname'], $params['categoryid']); $rc = new restore_controller($backupid, $newcourseid, backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id, backup::TARGET_NEW_COURSE); foreach ($backupsettings as $name => $value) { $setting = $rc->get_plan()->get_setting($name); if ($setting->get_status() == backup_setting::NOT_LOCKED) { $setting->set_value($value); } } if (!$rc->execute_precheck()) { $precheckresults = $rc->get_precheck_results(); if (is_array($precheckresults) && !empty($precheckresults['errors'])) { if (empty($CFG->keeptempdirectoriesonbackup)) { fulldelete($backupbasepath); } $errorinfo = ''; foreach ($precheckresults['errors'] as $error) { $errorinfo .= $error; } if (array_key_exists('warnings', $precheckresults)) { foreach ($precheckresults['warnings'] as $warning) { $errorinfo .= $warning; } } throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo); } } $rc->execute_plan(); $rc->destroy(); $course = $DB->get_record('course', array('id' => $newcourseid), '*', MUST_EXIST); $course->fullname = $params['fullname']; $course->shortname = $params['shortname']; $course->visible = $params['visible']; // Set shortname and fullname back. $DB->update_record('course', $course); if (empty($CFG->keeptempdirectoriesonbackup)) { fulldelete($backupbasepath); } // Delete the course backup file created by this WebService. Originally located in the course backups area. $file->delete(); return array('id' => $course->id, 'shortname' => $course->shortname); }
/** * Extracts the file. * * @param string|stored_file $source Archive file to extract * @return bool */ protected function extract_file_to_dir($source) { global $CFG, $USER; $this->filepath = restore_controller::get_tempdir_name($this->contextid, $USER->id); $fb = get_file_packer('application/vnd.moodle.backup'); $result = $fb->extract_to_pathname($source, $CFG->tempdir . '/backup/' . $this->filepath . '/', null, $this); // If any progress happened, end it. if ($this->startedprogress) { $this->get_progress_reporter()->end_progress(); } return $result; }
/** * Update imscp instance. * @param object $data * @param object $mform * @return bool true */ function imscp_update_instance($data, $mform) { global $CFG, $DB; require_once "{$CFG->dirroot}/mod/imscp/locallib.php"; $cmid = $data->coursemodule; $data->timemodified = time(); $data->id = $data->instance; $data->structure = null; // Better reparse structure after each update. $DB->update_record('imscp', $data); $context = context_module::instance($cmid); $imscp = $DB->get_record('imscp', array('id' => $data->id), '*', MUST_EXIST); if (!empty($data->package) && ($draftareainfo = file_get_draft_area_info($data->package)) && $draftareainfo['filecount']) { $fs = get_file_storage(); $imscp->revision++; $DB->update_record('imscp', $imscp); // Get a list of existing packages before adding new package. if ($imscp->keepold > -1) { $packages = $fs->get_area_files($context->id, 'mod_imscp', 'backup', false, "itemid ASC", false); } else { $packages = array(); } file_save_draft_area_files($data->package, $context->id, 'mod_imscp', 'backup', $imscp->revision, array('subdirs' => 0, 'maxfiles' => 1)); $files = $fs->get_area_files($context->id, 'mod_imscp', 'backup', $imscp->revision, '', false); $package = reset($files); // Purge all extracted content. $fs->delete_area_files($context->id, 'mod_imscp', 'content'); // Extract package content. if ($package) { $packer = get_file_packer('application/zip'); $package->extract_to_storage($packer, $context->id, 'mod_imscp', 'content', $imscp->revision, '/'); } // Cleanup old package files, keep current + keep old. while ($packages and count($packages) > $imscp->keepold) { $package = array_shift($packages); $fs->delete_area_files($context->id, 'mod_imscp', 'backup', $package->get_itemid()); } } $structure = imscp_parse_structure($imscp, $context); $imscp->structure = is_array($structure) ? serialize($structure) : null; $DB->update_record('imscp', $imscp); return true; }
/** * This function tests that the functions responsible for moving questions to * different contexts also updates the tag instances associated with the questions. */ public function test_altering_tag_instance_context() { global $CFG, $DB; // Set to admin user. $this->setAdminUser(); // Create two course categories - we are going to delete one of these later and will expect // all the questions belonging to the course in the deleted category to be moved. $coursecat1 = $this->getDataGenerator()->create_category(); $coursecat2 = $this->getDataGenerator()->create_category(); // Create a couple of categories and questions. $context1 = context_coursecat::instance($coursecat1->id); $context2 = context_coursecat::instance($coursecat2->id); $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $questioncat1 = $questiongenerator->create_question_category(array('contextid' => $context1->id)); $questioncat2 = $questiongenerator->create_question_category(array('contextid' => $context2->id)); $question1 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat1->id)); $question2 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat1->id)); $question3 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat2->id)); $question4 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat2->id)); // Now lets tag these questions. core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $context1, array('tag 1', 'tag 2')); core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $context1, array('tag 3', 'tag 4')); core_tag_tag::set_item_tags('core_question', 'question', $question3->id, $context2, array('tag 5', 'tag 6')); core_tag_tag::set_item_tags('core_question', 'question', $question4->id, $context2, array('tag 7', 'tag 8')); // Test moving the questions to another category. question_move_questions_to_category(array($question1->id, $question2->id), $questioncat2->id); // Test that all tag_instances belong to one context. $this->assertEquals(8, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat2->contextid))); // Test moving them back. question_move_questions_to_category(array($question1->id, $question2->id), $questioncat1->id); // Test that all tag_instances are now reset to how they were initially. $this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat1->contextid))); $this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat2->contextid))); // Now test moving a whole question category to another context. question_move_category_to_context($questioncat1->id, $questioncat1->contextid, $questioncat2->contextid); // Test that all tag_instances belong to one context. $this->assertEquals(8, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat2->contextid))); // Now test moving them back. question_move_category_to_context($questioncat1->id, $questioncat2->contextid, context_coursecat::instance($coursecat1->id)->id); // Test that all tag_instances are now reset to how they were initially. $this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat1->contextid))); $this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat2->contextid))); // Now we want to test deleting the course category and moving the questions to another category. question_delete_course_category($coursecat1, $coursecat2, false); // Test that all tag_instances belong to one context. $this->assertEquals(8, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat2->contextid))); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create some question categories and questions in this course. $coursecontext = context_course::instance($course->id); $questioncat = $questiongenerator->create_question_category(array('contextid' => $coursecontext->id)); $question1 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat->id)); $question2 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat->id)); // Add some tags to these questions. core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, array('tag 1', 'tag 2')); core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, array('tag 1', 'tag 2')); // Create a course that we are going to restore the other course to. $course2 = $this->getDataGenerator()->create_course(); // Create backup file and save it to the backup location. $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2); $bc->execute_plan(); $results = $bc->get_results(); $file = $results['backup_destination']; $fp = get_file_packer('application/vnd.moodle.backup'); $filepath = $CFG->dataroot . '/temp/backup/test-restore-course'; $file->extract_to_pathname($fp, $filepath); $bc->destroy(); // Now restore the course. $rc = new restore_controller('test-restore-course', $course2->id, backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2, backup::TARGET_NEW_COURSE); $rc->execute_precheck(); $rc->execute_plan(); // Get the created question category. $restoredcategory = $DB->get_record('question_categories', array('contextid' => context_course::instance($course2->id)->id), '*', MUST_EXIST); // Check that there are two questions in the restored to course's context. $this->assertEquals(2, $DB->count_records('question', array('category' => $restoredcategory->id))); $rc->destroy(); }
/** * The availability data format was changed in Moodle 2.7. This test * ensures that a Moodle 2.6 backup with this data can still be correctly * restored. */ public function test_restore_legacy_availability() { global $DB, $USER, $CFG; require_once $CFG->dirroot . '/grade/querylib.php'; require_once $CFG->libdir . '/completionlib.php'; $this->resetAfterTest(true); $this->setAdminUser(); $CFG->enableavailability = true; $CFG->enablecompletion = true; // Extract backup file. $backupid = 'abc'; $backuppath = $CFG->tempdir . '/backup/' . $backupid; check_dir_exists($backuppath); get_file_packer('application/vnd.moodle.backup')->extract_to_pathname(__DIR__ . '/fixtures/availability_26_format.mbz', $backuppath); // Do restore to new course with default settings. $generator = $this->getDataGenerator(); $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}"); $newcourseid = restore_dbops::create_new_course('Test fullname', 'Test shortname', $categoryid); $rc = new restore_controller($backupid, $newcourseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $USER->id, backup::TARGET_NEW_COURSE); $thrown = null; try { $this->assertTrue($rc->execute_precheck()); $rc->execute_plan(); $rc->destroy(); } catch (Exception $e) { $thrown = $e; // Because of the PHPUnit exception behaviour in this situation, we // will not see this message unless it is explicitly echoed (just // using it in a fail() call or similar will not work). echo "\n\nEXCEPTION: " . $thrown->getMessage() . '[' . $thrown->getFile() . ':' . $thrown->getLine() . "]\n\n"; } // Must set restore_controller variable to null so that php // garbage-collects it; otherwise the file will be left open and // attempts to delete it will cause a permission error on Windows // systems, breaking unit tests. $rc = null; $this->assertNull($thrown); // Get information about the resulting course and check that it is set // up correctly. $modinfo = get_fast_modinfo($newcourseid); $pages = array_values($modinfo->get_instances_of('page')); $forums = array_values($modinfo->get_instances_of('forum')); $quizzes = array_values($modinfo->get_instances_of('quiz')); $grouping = $DB->get_record('groupings', array('courseid' => $newcourseid)); // FROM date. $this->assertEquals('{"op":"&","showc":[true],"c":[{"type":"date","d":">=","t":1893456000}]}', $pages[1]->availability); // UNTIL date. $this->assertEquals('{"op":"&","showc":[false],"c":[{"type":"date","d":"<","t":1393977600}]}', $pages[2]->availability); // FROM and UNTIL. $this->assertEquals('{"op":"&","showc":[true,false],"c":[' . '{"type":"date","d":">=","t":1449705600},' . '{"type":"date","d":"<","t":1893456000}' . ']}', $pages[3]->availability); // Grade >= 75%. $grades = array_values(grade_get_grade_items_for_activity($quizzes[0], true)); $gradeid = $grades[0]->id; $coursegrade = grade_item::fetch_course_item($newcourseid); $this->assertEquals('{"op":"&","showc":[true],"c":[{"type":"grade","id":' . $gradeid . ',"min":75}]}', $pages[4]->availability); // Grade < 25%. $this->assertEquals('{"op":"&","showc":[true],"c":[{"type":"grade","id":' . $gradeid . ',"max":25}]}', $pages[5]->availability); // Grade 90-100%. $this->assertEquals('{"op":"&","showc":[true],"c":[{"type":"grade","id":' . $gradeid . ',"min":90,"max":100}]}', $pages[6]->availability); // Email contains frog. $this->assertEquals('{"op":"&","showc":[true],"c":[{"type":"profile","op":"contains","sf":"email","v":"frog"}]}', $pages[7]->availability); // Page marked complete.. $this->assertEquals('{"op":"&","showc":[true],"c":[{"type":"completion","cm":' . $pages[0]->id . ',"e":' . COMPLETION_COMPLETE . '}]}', $pages[8]->availability); // Quiz complete but failed. $this->assertEquals('{"op":"&","showc":[true],"c":[{"type":"completion","cm":' . $quizzes[0]->id . ',"e":' . COMPLETION_COMPLETE_FAIL . '}]}', $pages[9]->availability); // Quiz complete and succeeded. $this->assertEquals('{"op":"&","showc":[true],"c":[{"type":"completion","cm":' . $quizzes[0]->id . ',"e":' . COMPLETION_COMPLETE_PASS . '}]}', $pages[10]->availability); // Quiz not complete. $this->assertEquals('{"op":"&","showc":[true],"c":[{"type":"completion","cm":' . $quizzes[0]->id . ',"e":' . COMPLETION_INCOMPLETE . '}]}', $pages[11]->availability); // Grouping. $this->assertEquals('{"op":"&","showc":[false],"c":[{"type":"grouping","id":' . $grouping->id . '}]}', $pages[12]->availability); // All the options. $this->assertEquals('{"op":"&",' . '"showc":[false,true,false,true,true,true,true,true,true],' . '"c":[' . '{"type":"grouping","id":' . $grouping->id . '},' . '{"type":"date","d":">=","t":1488585600},' . '{"type":"date","d":"<","t":1709510400},' . '{"type":"profile","op":"contains","sf":"email","v":"@"},' . '{"type":"profile","op":"contains","sf":"city","v":"Frogtown"},' . '{"type":"grade","id":' . $gradeid . ',"min":30,"max":35},' . '{"type":"grade","id":' . $coursegrade->id . ',"min":5,"max":10},' . '{"type":"completion","cm":' . $pages[0]->id . ',"e":' . COMPLETION_COMPLETE . '},' . '{"type":"completion","cm":' . $quizzes[0]->id . ',"e":' . COMPLETION_INCOMPLETE . '}' . ']}', $pages[13]->availability); // Group members only forum. $this->assertEquals('{"op":"&","showc":[false],"c":[{"type":"group"}]}', $forums[0]->availability); // Section with lots of conditions. $this->assertEquals('{"op":"&","showc":[false,false,false,false],"c":[' . '{"type":"date","d":">=","t":1417737600},' . '{"type":"profile","op":"contains","sf":"email","v":"@"},' . '{"type":"grade","id":' . $gradeid . ',"min":20},' . '{"type":"completion","cm":' . $pages[0]->id . ',"e":' . COMPLETION_COMPLETE . '}]}', $modinfo->get_section_info(3)->availability); // Section with grouping. $this->assertEquals('{"op":"&","showc":[false],"c":[{"type":"grouping","id":' . $grouping->id . '}]}', $modinfo->get_section_info(4)->availability); }
/** * Extracts scrom package, sets up all variables. * Called whenever scorm changes * @param object $scorm instance - fields are updated and changes saved into database * @param bool $full force full update if true * @return void */ function scorm_parse($scorm, $full) { global $CFG, $DB; $cfg_scorm = get_config('scorm'); if (!isset($scorm->cmid)) { $cm = get_coursemodule_from_instance('scorm', $scorm->id); $scorm->cmid = $cm->id; } $context = context_module::instance($scorm->cmid); $newhash = $scorm->sha1hash; if ($scorm->scormtype === SCORM_TYPE_LOCAL or $scorm->scormtype === SCORM_TYPE_LOCALSYNC) { $fs = get_file_storage(); $packagefile = false; $packagefileimsmanifest = false; if ($scorm->scormtype === SCORM_TYPE_LOCAL) { if ($packagefile = $fs->get_file($context->id, 'mod_scorm', 'package', 0, '/', $scorm->reference)) { if ($packagefile->is_external_file()) { // Get zip file so we can check it is correct. $packagefile->import_external_file_contents(); } $newhash = $packagefile->get_contenthash(); if (strtolower($packagefile->get_filename()) == 'imsmanifest.xml') { $packagefileimsmanifest = true; } } else { $newhash = null; } } else { if (!$cfg_scorm->allowtypelocalsync) { // sorry - localsync disabled return; } if ($scorm->reference !== '' and (!$full or $scorm->sha1hash !== sha1($scorm->reference))) { $fs->delete_area_files($context->id, 'mod_scorm', 'package'); $file_record = array('contextid' => $context->id, 'component' => 'mod_scorm', 'filearea' => 'package', 'itemid' => 0, 'filepath' => '/'); if ($packagefile = $fs->create_file_from_url($file_record, $scorm->reference, array('calctimeout' => true))) { $newhash = sha1($scorm->reference); } else { $newhash = null; } } } if ($packagefile) { if (!$full and $packagefile and $scorm->sha1hash === $newhash) { if (strpos($scorm->version, 'SCORM') !== false) { if ($packagefileimsmanifest || $fs->get_file($context->id, 'mod_scorm', 'content', 0, '/', 'imsmanifest.xml')) { // No need to update. return; } } else { if (strpos($scorm->version, 'AICC') !== false) { // TODO: add more sanity checks - something really exists in scorm_content area return; } } } if (!$packagefileimsmanifest) { // Now extract files. $fs->delete_area_files($context->id, 'mod_scorm', 'content'); $packer = get_file_packer('application/zip'); $packagefile->extract_to_storage($packer, $context->id, 'mod_scorm', 'content', 0, '/'); } } else { if (!$full) { return; } } if ($packagefileimsmanifest) { require_once "{$CFG->dirroot}/mod/scorm/datamodels/scormlib.php"; // Direct link to imsmanifest.xml file. if (!scorm_parse_scorm($scorm, $packagefile)) { $scorm->version = 'ERROR'; } } else { if ($manifest = $fs->get_file($context->id, 'mod_scorm', 'content', 0, '/', 'imsmanifest.xml')) { require_once "{$CFG->dirroot}/mod/scorm/datamodels/scormlib.php"; // SCORM if (!scorm_parse_scorm($scorm, $manifest)) { $scorm->version = 'ERROR'; } } else { require_once "{$CFG->dirroot}/mod/scorm/datamodels/aicclib.php"; // AICC if (!scorm_parse_aicc($scorm)) { $scorm->version = 'ERROR'; } $scorm->version = 'AICC'; } } } else { if ($scorm->scormtype === SCORM_TYPE_EXTERNAL and $cfg_scorm->allowtypeexternal) { require_once "{$CFG->dirroot}/mod/scorm/datamodels/scormlib.php"; // SCORM only, AICC can not be external if (!scorm_parse_scorm($scorm, $scorm->reference)) { $scorm->version = 'ERROR'; } $newhash = sha1($scorm->reference); } else { if ($scorm->scormtype === SCORM_TYPE_AICCURL and $cfg_scorm->allowtypeexternalaicc) { require_once "{$CFG->dirroot}/mod/scorm/datamodels/aicclib.php"; // AICC if (!scorm_parse_aicc($scorm)) { $scorm->version = 'ERROR'; } $scorm->version = 'AICC'; } else { // sorry, disabled type return; } } } $scorm->revision++; $scorm->sha1hash = $newhash; $DB->update_record('scorm', $scorm); }
/** * Load and format all the needed information from a backup file. * * This will only extract the moodle_backup.xml file from an MBZ * file and then call {@link self::get_backup_information()}. * * @param string $filepath absolute path to the MBZ file. * @return stdClass containing information. * @since 2.4 */ public static function get_backup_information_from_mbz($filepath) { global $CFG; if (!is_readable($filepath)) { throw new backup_helper_exception('missing_moodle_backup_file', $filepath); } // Extract moodle_backup.xml. $tmpname = 'info_from_mbz_' . time() . '_' . random_string(4); $tmpdir = $CFG->tempdir . '/backup/' . $tmpname; $fp = get_file_packer('application/vnd.moodle.backup'); $extracted = $fp->extract_to_pathname($filepath, $tmpdir, array('moodle_backup.xml')); $moodlefile = $tmpdir . '/' . 'moodle_backup.xml'; if (!$extracted || !is_readable($moodlefile)) { throw new backup_helper_exception('missing_moodle_backup_xml_file', $moodlefile); } // Read the information and delete the temporary directory. $info = self::get_backup_information($tmpname); remove_dir($tmpdir); return $info; }