dirroot . '/backup/util/includes/backup_includes.php'); require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php"); require_once($CFG->libdir . '/clilib.php'); $usage = "Import a course from ContentMonster Usage: # php import_cli.php --courseid= --categoryid= --timestamp= [--source=] # php import_cli.php [--help|-h] Options: -h --help Print this help. --paramname= Describe the parameter and the meaning of its values. "; list($options, $unrecognised) = cli_get_params([ 'help' => false, 'courseid' => null, 'categoryid' => null, 'timestamp' => null, 'source' => null, ], [ 'h' => 'help' ]); if ($unrecognised) { $unrecognised = implode(PHP_EOL . ' ', $unrecognised); cli_error(get_string('cliunknowoption', 'core_admin', $unrecognised)); } if ($options['help']) { cli_writeln($usage); exit(2); } if (empty($options['courseid'])) { cli_error('Missing mandatory argument courseid.', 2); } if (empty($options['categoryid'])) { cli_error('Missing mandatory argument categoryid.', 2); } if (empty($options['timestamp'])) { cli_error('Missing mandatory argument timestamp.', 2); } function generateRandomString($length = 10) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } return $randomString; } function removePath($path) { if(is_dir($path)) { $handler = opendir($path); if (!$handler) { trigger_error('File Error: Failed to open the directory ' . $path, E_USER_ERROR); return; } // list the files in the directory while ($file = readdir($handler)) { if ($file != '.' && $file != '..') removePath($path.DIRECTORY_SEPARATOR.$file); } // tidy up: close the handler closedir($handler); if (!rmdir($path)) { trigger_error('File Error: Failed to remove folder ' . $path, E_USER_ERROR); } } else { // delete it if (!unlink($path)) { trigger_error('File Error: Failed to remove file ' . $path, E_USER_ERROR); } } } $courseid = $options['courseid']; $categoryid = $options["categoryid"]; $timestamp = $options["timestamp"]; try { $course = get_course($courseid); } catch (Exception $ex) { $course = null; } try { $category = $DB->get_record('course_categories', array('id' => $categoryid), '*', MUST_EXIST); } catch (Exception $ex) { cli_error('Category " . $categoryid . " does not exist.'); } if (!$course) { while (!$DB->get_record('course', array('id' => ((int) $courseid) - 1), '*')) { $name = generateRandomString(); $newcourse = restore_dbops::create_new_course("Placeholder " . $name, $name, $category->id); if ((int) $newcourse > (int) $courseid) { cli_error('Did you delete courses by any chance? Cannot create course ' . $courseid . '.'); } } } $replicationconfig = get_config('local_replication'); $directory = $replicationconfig->directory; $infile = $directory . DIRECTORY_SEPARATOR . "course_" . $courseid . "_" . $categoryid . "_" . $timestamp . ".mbz"; if (empty($CFG->tempdir)) { $CFG->tempdir = $CFG->dataroot . DIRECTORY_SEPARATOR . 'temp'; } if (!file_exists($infile)) { cli_error("Backup file '" . $infile . "' does not exist."); } if (!is_readable($infile)) { cli_error("Backup file '" . $infile . "' is not readable."); } $backupdir = "restore_" . uniqid(); if (isset($CFG->backuptempdir)){ $path = $CFG->backuptempdir . DIRECTORY_SEPARATOR . $backupdir; } else{ $path = $CFG->tempdir . DIRECTORY_SEPARATOR . "backup" . DIRECTORY_SEPARATOR . $backupdir; } $fp = get_file_packer('application/vnd.moodle.backup'); $fp->extract_to_pathname($infile, $path); $xmlfile = $path . DIRECTORY_SEPARATOR . "course" . DIRECTORY_SEPARATOR . "course.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 (!$fullname) { $fullname = $shortname; } $questionfile = $path . DIRECTORY_SEPARATOR . "questions.xml"; if (file_exists($questionfile)) { $questions = new DOMDocument(); $questions->load($questionfile); $questions->save($questionfile . ".bak"); foreach ($questions->getElementsByTagName("question") as $question) { $questiontext = $question->getElementsByTagName("questiontext")->item(0); $newquestiontext = strip_tags(html_entity_decode($questiontext->textContent)); $questiontext->removeChild($questiontext->firstChild); $questiontext->appendChild(new DOMText($newquestiontext)); foreach ($question->getElementsByTagName("answer") as $answer) { $answertext = $answer->getElementsByTagName("answertext")->item(0); $newanswertext = strip_tags(html_entity_decode($answertext->textContent)); $answertext->removeChild($answertext->firstChild); $answertext->appendChild(new DOMText($newanswertext)); } } $questions->save($questionfile); } if (!$course && $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 ($course) { cli_writeln("Overwriting current content of existing course -> Course ID: $courseid"); $rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2, 0); $rc->get_plan()->get_setting('overwrite_conf')->set_value(true); $rc->get_plan()->get_setting('keep_roles_and_enrolments')->set_value(true); $rc->get_plan()->get_setting('keep_groups_and_groupings')->set_value(true); } else { cli_writeln("Creating new course to restore backup"); $courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id); $rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2, backup::TARGET_NEW_COURSE); } if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) { $rc->convert(); } $plan = $rc->get_plan(); if (!$rc->execute_precheck()){ $check = $rc->get_precheck_results(); cli_error("Restore pre-check failed!"); } $deletingoptions = array(); $deletingoptions['keep_roles_and_enrolments'] = 1; $deletingoptions['keep_groups_and_groupings'] = 1; restore_dbops::delete_course_content($courseid, $deletingoptions); $rc->execute_plan(); $rc->destroy(); $course = get_course($courseid); $course->category = $categoryid; $course->fullname = $fullname; $course->shortname = $shortname; $DB->update_record('course', $course); removePath($path); cli_writeln("New course ID for '$shortname': $courseid in category {$category->id}"); cli_writeln("OK");