function scorm_check_package($data) { global $CFG, $COURSE; require_once $CFG->libdir . '/filelib.php'; $courseid = $data->course; // Course Module ID $reference = $data->reference; // Package path $scormid = $data->instance; // scorm ID $validation = new stdClass(); if (!empty($courseid) && !empty($reference)) { $externalpackage = scorm_external_link($reference); $validation->launch = 0; $referencefield = $reference; if (empty($reference)) { $validation = null; } else { if ($reference[0] == '#') { if (isset($CFG->repositoryactivate) && $CFG->repositoryactivate) { $referencefield = $reference . '/imsmanifest.xml'; $reference = $CFG->repository . substr($reference, 1) . '/imsmanifest.xml'; } else { $validation = null; } } else { if (!$externalpackage) { $reference = $CFG->dataroot . '/' . $courseid . '/' . $reference; } } } if (!empty($scormid)) { // // SCORM Update // if (!empty($validation) && (is_file($reference) || $externalpackage)) { if (!$externalpackage) { $mdcheck = md5_file($reference); } else { if ($externalpackage) { if ($scormdir = make_upload_directory("{$courseid}/{$CFG->moddata}/scorm")) { if ($tempdir = scorm_tempdir($scormdir)) { $content = download_file_content($reference); $file = fopen($tempdir . '/' . basename($reference), 'x'); fwrite($file, $content); fclose($file); $mdcheck = md5_file($tempdir . '/' . basename($reference)); scorm_delete_files($tempdir); } } } } if ($scorm = get_record('scorm', 'id', $scormid)) { if ($scorm->reference[0] == '#') { if (isset($CFG->repositoryactivate) && $CFG->repositoryactivate) { $oldreference = $CFG->repository . substr($scorm->reference, 1) . '/imsmanifest.xml'; } else { $oldreference = $scorm->reference; } } else { if (!scorm_external_link($scorm->reference)) { $oldreference = $CFG->dataroot . '/' . $courseid . '/' . $scorm->reference; } else { $oldreference = $scorm->reference; } } $validation->launch = $scorm->launch; if ($oldreference == $reference && $mdcheck != $scorm->md5hash || $oldreference != $reference) { // This is a new or a modified package $validation->launch = 0; } else { // Old package already validated if (strpos($scorm->version, 'AICC') !== false) { $validation->pkgtype = 'AICC'; } else { $validation->pkgtype = 'SCORM'; } } } else { $validation = null; } } else { $validation = null; } } //$validation->launch = 0; if ($validation != null && $validation->launch == 0) { // // Package must be validated // $ext = strtolower(substr(basename($reference), strrpos(basename($reference), '.'))); $tempdir = ''; switch ($ext) { case '.pif': case '.zip': // Create a temporary directory to unzip package and validate package $scormdir = ''; if ($scormdir = make_upload_directory("{$courseid}/{$CFG->moddata}/scorm")) { if ($tempdir = scorm_tempdir($scormdir)) { if ($externalpackage) { $content = download_file_content($reference); $file = fopen($tempdir . '/' . basename($reference), 'x'); fwrite($file, $content); fclose($file); } else { copy("{$reference}", $tempdir . '/' . basename($reference)); } unzip_file($tempdir . '/' . basename($reference), $tempdir, false); if (!$externalpackage) { unlink($tempdir . '/' . basename($reference)); } if (is_file($tempdir . '/imsmanifest.xml')) { $validation = scorm_validate_manifest($tempdir . '/imsmanifest.xml'); $validation->pkgtype = 'SCORM'; } else { $validation = scorm_validate_aicc($tempdir); $validation->pkgtype = 'AICC'; } } else { $validation = null; } } else { $validation = null; } break; case '.xml': if (basename($reference) == 'imsmanifest.xml') { if ($externalpackage) { if ($scormdir = make_upload_directory("{$courseid}/{$CFG->moddata}/scorm")) { if ($tempdir = scorm_tempdir($scormdir)) { $content = download_file_content($reference); $file = fopen($tempdir . '/' . basename($reference), 'x'); fwrite($file, $content); fclose($file); if (is_file($tempdir . '/' . basename($reference))) { $validation = scorm_validate_manifest($tempdir . '/' . basename($reference)); } else { $validation = null; } } } } else { $validation = scorm_validate_manifest($reference); } $validation->pkgtype = 'SCORM'; } else { $validation = null; } break; default: $validation = null; break; } if ($validation == null) { if (is_dir($tempdir)) { // Delete files and temporary directory scorm_delete_files($tempdir); } } else { if ($ext == '.xml' && !$externalpackage) { $validation->datadir = dirname($referencefield); } else { $validation->datadir = substr($tempdir, strlen($scormdir)); } $validation->launch = 0; } } } else { $validation = null; } return $validation; }
/** * Given an object containing all the necessary data, * (defined by the form in mod.html) this function * will update an existing instance with new data. * * @param mixed $scorm Form data * @return int */ function scorm_update_instance($scorm) { global $CFG; require_once 'locallib.php'; $scorm->parse = 0; if (($packagedata = scorm_check_package($scorm)) != null) { $scorm->pkgtype = $packagedata->pkgtype; if ($packagedata->launch == 0) { $scorm->launch = $packagedata->launch; $scorm->datadir = $packagedata->datadir; $scorm->parse = 1; if (!scorm_external_link($scorm->reference)) { $scorm->md5hash = md5_file($CFG->dataroot . '/' . $scorm->course . '/' . $scorm->reference); } else { $scorm->dir = $CFG->dataroot . '/' . $scorm->course . '/moddata/scorm'; $scorm->md5hash = md5_file($scorm->dir . $scorm->datadir . '/' . basename($scorm->reference)); } } } $scorm->timemodified = time(); $scorm->id = $scorm->instance; $scorm = scorm_option2text($scorm); $scorm->width = str_replace('%', '', $scorm->width); $scorm->height = str_replace('%', '', $scorm->height); if (!isset($scorm->whatgrade)) { $scorm->whatgrade = 0; } $scorm->grademethod = $scorm->whatgrade * 10 + $scorm->grademethod; // Check if scorm manifest needs to be reparsed if ($scorm->parse == 1) { $scorm->dir = $CFG->dataroot . '/' . $scorm->course . '/moddata/scorm'; if (is_dir($scorm->dir . '/' . $scorm->id)) { scorm_delete_files($scorm->dir . '/' . $scorm->id); } if (isset($scorm->datadir) && $scorm->datadir != $scorm->id && (scorm_external_link($scorm->reference) || basename($scorm->reference) != 'imsmanifest.xml' && $scorm->reference[0] != '#')) { rename($scorm->dir . $scorm->datadir, $scorm->dir . '/' . $scorm->id); } $scorm->launch = scorm_parse($scorm); } else { $oldscorm = get_record('scorm', 'id', $scorm->id); $scorm->reference = $oldscorm->reference; // This fix a problem with Firefox when the teacher choose Cancel on overwrite question } if ($result = update_record('scorm', $scorm)) { scorm_grade_item_update(stripslashes_recursive($scorm)); } return $result; }
} else { if (isset($sco->parameters) && !empty($sco->parameters)) { $launcher = $sco->launch . $connector . $sco->parameters; } else { $launcher = $sco->launch; } } if (scorm_external_link($sco->launch)) { // Remote learning activity $result = $launcher; } else { if ($scorm->reference[0] == '#') { // Repository $result = $CFG->repositorywebroot . substr($scorm->reference, 1) . '/' . $sco->launch; } else { if (basename($scorm->reference) == 'imsmanifest.xml' && scorm_external_link($scorm->reference)) { // Remote manifest $result = dirname($scorm->reference) . '/' . $launcher; } else { // Moodle internal package/manifest or remote (auto-imported) package if (basename($scorm->reference) == 'imsmanifest.xml') { $basedir = dirname($scorm->reference); } else { $basedir = $CFG->moddata . '/scorm/' . $scorm->id; } //note: do not convert this to use get_file_url()! // SCORM does not work without slasharguments anyway and there might be some extra ?xx=yy params // see MDL-16060 $result = $CFG->wwwroot . '/file.php/' . $scorm->course . '/' . $basedir . '/' . $launcher; } }
$sco->parameters = substr($sco->parameters, 1); } } if ($version == 'AICC') { if (isset($sco->parameters) && !empty($sco->parameters)) { $sco->parameters = '&' . $sco->parameters; } $launcher = $sco->launch . $connector . 'aicc_sid=' . sesskey() . '&aicc_url=' . $CFG->wwwroot . '/mod/scorm/aicc.php' . $sco->parameters; } else { if (isset($sco->parameters) && !empty($sco->parameters)) { $launcher = $sco->launch . $connector . $sco->parameters; } else { $launcher = $sco->launch; } } if (scorm_external_link($sco->launch)) { //TODO: does this happen? $result = $launcher; } else { if ($scorm->scormtype === SCORM_TYPE_EXTERNAL) { // Remote learning activity $result = dirname($scorm->reference) . '/' . $launcher; } else { if ($scorm->scormtype === SCORM_TYPE_IMSREPOSITORY) { // Repository $result = $CFG->repositorywebroot . substr($scorm->reference, 1) . '/' . $sco->launch; } else { if ($scorm->scormtype === SCORM_TYPE_LOCAL or $scorm->scormtype === SCORM_TYPE_LOCALSYNC) { //note: do not convert this to use get_file_url()! // SCORM does not work without slasharguments anyway and there might be some extra ?xx=yy params // see MDL-16060
/** * Return a SCO object and the SCO launch URL * * @param stdClass $scorm SCORM object * @param int $scoid The SCO id in database * @param stdClass $context context object * @return array the SCO object and URL * @since Moodle 3.1 */ function scorm_get_sco_and_launch_url($scorm, $scoid, $context) { global $CFG, $DB; if (!empty($scoid)) { // Direct SCO request. if ($sco = scorm_get_sco($scoid)) { if ($sco->launch == '') { // Search for the next launchable sco. if ($scoes = $DB->get_records_select( 'scorm_scoes', 'scorm = ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true).' AND id > ?', array($scorm->id, $sco->id), 'sortorder, id')) { $sco = current($scoes); } } } } // If no sco was found get the first of SCORM package. if (!isset($sco)) { $scoes = $DB->get_records_select( 'scorm_scoes', 'scorm = ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true), array($scorm->id), 'sortorder, id' ); $sco = current($scoes); } $connector = ''; $version = substr($scorm->version, 0, 4); if ((isset($sco->parameters) && (!empty($sco->parameters))) || ($version == 'AICC')) { if (stripos($sco->launch, '?') !== false) { $connector = '&'; } else { $connector = '?'; } if ((isset($sco->parameters) && (!empty($sco->parameters))) && ($sco->parameters[0] == '?')) { $sco->parameters = substr($sco->parameters, 1); } } if ($version == 'AICC') { require_once("$CFG->dirroot/mod/scorm/datamodels/aicclib.php"); $aiccsid = scorm_aicc_get_hacp_session($scorm->id); if (empty($aiccsid)) { $aiccsid = sesskey(); } $scoparams = ''; if (isset($sco->parameters) && (!empty($sco->parameters))) { $scoparams = '&'. $sco->parameters; } $launcher = $sco->launch.$connector.'aicc_sid='.$aiccsid.'&aicc_url='.$CFG->wwwroot.'/mod/scorm/aicc.php'.$scoparams; } else { if (isset($sco->parameters) && (!empty($sco->parameters))) { $launcher = $sco->launch.$connector.$sco->parameters; } else { $launcher = $sco->launch; } } if (scorm_external_link($sco->launch)) { // TODO: does this happen? $scolaunchurl = $launcher; } else if ($scorm->scormtype === SCORM_TYPE_EXTERNAL) { // Remote learning activity. $scolaunchurl = dirname($scorm->reference).'/'.$launcher; } else if ($scorm->scormtype === SCORM_TYPE_LOCAL && strtolower($scorm->reference) == 'imsmanifest.xml') { // This SCORM content sits in a repository that allows relative links. $scolaunchurl = "$CFG->wwwroot/pluginfile.php/$context->id/mod_scorm/imsmanifest/$scorm->revision/$launcher"; } else if ($scorm->scormtype === SCORM_TYPE_LOCAL or $scorm->scormtype === SCORM_TYPE_LOCALSYNC) { // Note: do not convert this to use moodle_url(). // SCORM does not work without slasharguments and moodle_url() encodes querystring vars. $scolaunchurl = "$CFG->wwwroot/pluginfile.php/$context->id/mod_scorm/content/$scorm->revision/$launcher"; } return array($sco, $scolaunchurl); }