MDL-16088 scorm new file api conversion

This commit is contained in:
skodak 2008-09-09 08:30:00 +00:00
parent fec2094ee6
commit 9528568bf0
12 changed files with 993 additions and 832 deletions

View File

@ -4,6 +4,12 @@
$string['activation'] = 'Activation';
$string['advanced'] = 'Parameters';
$string['allowtypeexternal'] = 'Enable external package type';
$string['allowtypeimsrepository'] = 'Enable IMS package type';
$string['allowtypelocalsync'] = 'Enable downloaded package type';
$string['areaintro'] = 'Introduction files';
$string['areacontent'] = 'Content files';
$string['areapackage'] = 'Package file';
$string['asset'] = 'Asset';
$string['assetlaunched'] = 'Asset - Viewed';
$string['attempt'] = 'attempt';
@ -125,6 +131,7 @@ $string['scorm:skipview'] = 'Skip overview';
$string['scorm:viewreport'] = 'View reports';
$string['scorm:viewscores'] = 'View scores';
$string['scormcourse'] = 'Learning Course';
$string['scormtype'] = 'Type';
$string['scrollbars'] = 'Allow the window to be scrolled';
$string['sided'] = 'On the left side';
$string['skipview'] = 'Student skip content structure page';
@ -145,6 +152,12 @@ $string['toolbar'] = 'Show the toolbar';
$string['totaltime'] = 'Time';
$string['trackingloose'] = 'WARNING: The tracking data of this package will be lost!';
$string['type'] = 'Type';
$string['typeexternal'] = 'External SCORM manifest';
$string['typeimsrepository'] = 'Local IMS content repository';
$string['typelocal'] = 'Uploaded package';
$string['typelocalsync'] = 'Downloaded package';
$string['updatetime'] = 'Synchronisation time';
$string['url'] = 'URL';
$string['validateascorm'] = 'Validate a package';
$string['validation'] = 'Validation result';
$string['validationtype'] = 'This preference set the DOMXML library used for validating SCORM Manifest. If you don\'t know leave the selected choice.';

View File

@ -2,7 +2,7 @@
require_once("../../config.php");
require_once('locallib.php');
$id = optional_param('id', '', PARAM_INT); // Course Module ID, or
$a = optional_param('a', '', PARAM_INT); // scorm ID
$scoid = required_param('scoid', PARAM_INT); // sco ID
@ -33,7 +33,7 @@
print_error('missingparameter');
}
require_login($course->id, false, $cm);
require_login($course, false, $cm);
if ($usertrack = scorm_get_tracks($scoid,$USER->id,$attempt)) {
if ((isset($usertrack->{'cmi.exit'}) && ($usertrack->{'cmi.exit'} != 'time-out')) || ($scorm->version != "SCORM_1.3")) {
@ -58,7 +58,7 @@
$userdata->credit = 'credit';
} else {
$userdata->credit = 'no-credit';
}
}
if ($scodatas = scorm_get_sco($scoid, SCO_DATA)) {
foreach ($scodatas as $key => $value) {
$userdata->$key = addslashes_js($value);

View File

@ -90,49 +90,57 @@ function scorm_forge_cols_regexp($columns,$remodule='(".*")?,') {
return $regexp;
}
function scorm_parse_aicc($pkgdir,$scormid) {
function scorm_parse_aicc($scorm) {
global $DB;
if (!isset($scorm->cmid)) {
$cm = get_coursemodule_from_instance('scorm', $scorm->id);
$scorm->cmid = $cm->id;
}
$context = get_context_instance(COURSE_MODULE, $scorm->cmid);
$fs = get_file_storage();
$files = $fs->get_area_files($context->id, 'scorm_content', 0, '', false);
$version = 'AICC';
$ids = array();
$courses = array();
$extaiccfiles = array('crs','des','au','cst','ort','pre','cmp');
if ($handle = opendir($pkgdir)) {
while (($file = readdir($handle)) !== false) {
if ($file[0] != '.') {
$ext = substr($file,strrpos($file,'.'));
$extension = strtolower(substr($ext,1));
if (in_array($extension,$extaiccfiles)) {
$id = strtolower(basename($file,$ext));
$ids[$id]->$extension = $file;
}
}
foreach ($files as $file) {
$filename = $file->get_filename();
$ext = substr($filename,strrpos($filename,'.'));
$extension = strtolower(substr($ext,1));
if (in_array($extension,$extaiccfiles)) {
$id = strtolower(basename($filename,$ext));
$ids[$id]->$extension = $file;
}
closedir($handle);
}
foreach ($ids as $courseid => $id) {
if (isset($id->crs)) {
if (is_file($pkgdir.'/'.$id->crs)) {
$rows = file($pkgdir.'/'.$id->crs);
foreach ($rows as $row) {
if (preg_match("/^(.+)=(.+)$/",$row,$matches)) {
switch (strtolower(trim($matches[1]))) {
case 'course_id':
$courses[$courseid]->id = trim($matches[2]);
break;
case 'course_title':
$courses[$courseid]->title = trim($matches[2]);
break;
case 'version':
$courses[$courseid]->version = 'AICC_'.trim($matches[2]);
break;
}
$rows = $id->crs->get_content();
foreach ($rows as $row) {
if (preg_match("/^(.+)=(.+)$/",$row,$matches)) {
switch (strtolower(trim($matches[1]))) {
case 'course_id':
$courses[$courseid]->id = trim($matches[2]);
break;
case 'course_title':
$courses[$courseid]->title = trim($matches[2]);
break;
case 'version':
$courses[$courseid]->version = 'AICC_'.trim($matches[2]);
break;
}
}
}
}
if (isset($id->des)) {
$rows = file($pkgdir.'/'.$id->des);
$rows = $id->des->get_content();
$columns = scorm_get_aicc_columns($rows[0]);
$regexp = scorm_forge_cols_regexp($columns->columns);
for ($i=1;$i<count($rows);$i++) {
@ -145,7 +153,7 @@ function scorm_parse_aicc($pkgdir,$scormid) {
}
}
if (isset($id->au)) {
$rows = file($pkgdir.'/'.$id->au);
$rows = $id->au->get_content();
$columns = scorm_get_aicc_columns($rows[0]);
$regexp = scorm_forge_cols_regexp($columns->columns);
for ($i=1;$i<count($rows);$i++) {
@ -158,7 +166,7 @@ function scorm_parse_aicc($pkgdir,$scormid) {
}
}
if (isset($id->cst)) {
$rows = file($pkgdir.'/'.$id->cst);
$rows = $id->cst->get_content();
$columns = scorm_get_aicc_columns($rows[0],'block');
$regexp = scorm_forge_cols_regexp($columns->columns,'(.+)?,');
for ($i=1;$i<count($rows);$i++) {
@ -172,7 +180,7 @@ function scorm_parse_aicc($pkgdir,$scormid) {
}
}
if (isset($id->ort)) {
$rows = file($pkgdir.'/'.$id->ort);
$rows = $id->ort->get_content();
$columns = scorm_get_aicc_columns($rows[0],'course_element');
$regexp = scorm_forge_cols_regexp($columns->columns,'(.+)?,');
for ($i=1;$i<count($rows);$i++) {
@ -186,7 +194,7 @@ function scorm_parse_aicc($pkgdir,$scormid) {
}
}
if (isset($id->pre)) {
$rows = file($pkgdir.'/'.$id->pre);
$rows = $id->pre->get_content();
$columns = scorm_get_aicc_columns($rows[0],'structure_element');
$regexp = scorm_forge_cols_regexp($columns->columns,'(.+),');
for ($i=1;$i<count($rows);$i++) {
@ -196,19 +204,19 @@ function scorm_parse_aicc($pkgdir,$scormid) {
}
}
if (isset($id->cmp)) {
$rows = file($pkgdir.'/'.$id->cmp);
$rows = $id->cmp->get_content();
}
}
//print_r($courses);
$oldscoes = $DB->get_records('scorm_scoes', array('scorm'=>$scormid));
$oldscoes = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id));
$launch = 0;
if (isset($courses)) {
foreach ($courses as $course) {
$sco = new object();
$sco->identifier = $course->id;
$sco->scorm = $scormid;
$sco->scorm = $scorm->id;
$sco->organization = '';
$sco->title = $course->title;
$sco->parent = '/';
@ -216,7 +224,7 @@ function scorm_parse_aicc($pkgdir,$scormid) {
$sco->scormtype = '';
//print_r($sco);
if ($ss = $DB->get_record('scorm_scoes', array('scorm'=>$scormid,'identifier'=>$sco->identifier))) {
if ($ss = $DB->get_record('scorm_scoes', array('scorm'=>$scorm->id,'identifier'=>$sco->identifier))) {
$id = $ss->id;
$DB->update_record('scorm_scoes',$sco);
unset($oldscoes[$id]);
@ -231,7 +239,7 @@ function scorm_parse_aicc($pkgdir,$scormid) {
foreach($course->elements as $element) {
unset($sco);
$sco->identifier = $element->system_id;
$sco->scorm = $scormid;
$sco->scorm = $scorm->id;
$sco->organization = $course->id;
$sco->title = $element->title;
@ -302,8 +310,12 @@ function scorm_parse_aicc($pkgdir,$scormid) {
$DB->delete_records('scorm_scoes_track', array('scoid'=>$oldsco->id));
}
}
$DB->set_field('scorm','version','AICC', array('id'=>$scormid));
return $launch;
$scorm->version = 'AICC';
$scorm->launch = $launch;
return true;
}
function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='normal',$attempt='',$play=false) {

View File

@ -456,161 +456,165 @@ function scorm_get_manifest($blocks,$scoes) {
return $scoes;
}
function scorm_parse_scorm($pkgdir,$scormid) {
function scorm_parse_scorm($scorm, $manifest) {
global $CFG, $DB;
// load manifest into string
if ($manifest instanceof stored_file) {
$xmltext = $manifest->get_content();
} else {
require_once "$CFG->libdir/filelib.php";
$xmltext = download_file_content($manifest);
}
$launch = 0;
$manifestfile = $pkgdir.'/imsmanifest.xml';
if (is_file($manifestfile)) {
$xmltext = file_get_contents($manifestfile);
$pattern = '/&(?!\w{2,6};)/';
$replacement = '&amp;';
$xmltext = preg_replace($pattern, $replacement, $xmltext);
$pattern = '/&(?!\w{2,6};)/';
$replacement = '&amp;';
$xmltext = preg_replace($pattern, $replacement, $xmltext);
$objXML = new xml2Array();
$manifests = $objXML->parse($xmltext);
$objXML = new xml2Array();
$manifests = $objXML->parse($xmltext);
//print_object($manifests);
$scoes = new stdClass();
$scoes->version = '';
$scoes = scorm_get_manifest($manifests,$scoes);
$scoes = new stdClass();
$scoes->version = '';
$scoes = scorm_get_manifest($manifests,$scoes);
//print_object($scoes);
if (count($scoes->elements) > 0) {
$olditems = $DB->get_records('scorm_scoes', array('scorm'=>$scormid));
foreach ($scoes->elements as $manifest => $organizations) {
foreach ($organizations as $organization => $items) {
foreach ($items as $identifier => $item) {
// This new db mngt will support all SCORM future extensions
$newitem = new stdClass();
$newitem->scorm = $scormid;
$newitem->manifest = $manifest;
$newitem->organization = $organization;
$standarddatas = array('parent', 'identifier', 'launch', 'scormtype', 'title');
foreach ($standarddatas as $standarddata) {
if (isset($item->$standarddata)) {
$newitem->$standarddata = $item->$standarddata;
if (count($scoes->elements) > 0) {
$olditems = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id));
foreach ($scoes->elements as $manifest => $organizations) {
foreach ($organizations as $organization => $items) {
foreach ($items as $identifier => $item) {
// This new db mngt will support all SCORM future extensions
$newitem = new stdClass();
$newitem->scorm = $scorm->id;
$newitem->manifest = $manifest;
$newitem->organization = $organization;
$standarddatas = array('parent', 'identifier', 'launch', 'scormtype', 'title');
foreach ($standarddatas as $standarddata) {
if (isset($item->$standarddata)) {
$newitem->$standarddata = $item->$standarddata;
}
}
// Insert the new SCO, and retain the link between the old and new for later adjustment
$id = $DB->insert_record('scorm_scoes',$newitem);
if (!empty($olditems) && ($olditemid = scorm_array_search('identifier',$newitem->identifier,$olditems))) {
$olditems[$olditemid]->newid = $id;
}
if ($optionaldatas = scorm_optionals_data($item,$standarddatas)) {
$data = new stdClass();
$data->scoid = $id;
foreach ($optionaldatas as $optionaldata) {
if (isset($item->$optionaldata)) {
$data->name = $optionaldata;
$data->value = $item->$optionaldata;
$dataid = $DB->insert_record('scorm_scoes_data',$data);
}
}
// Insert the new SCO, and retain the link between the old and new for later adjustment
$id = $DB->insert_record('scorm_scoes',$newitem);
if (!empty($olditems) && ($olditemid = scorm_array_search('identifier',$newitem->identifier,$olditems))) {
$olditems[$olditemid]->newid = $id;
}
if ($optionaldatas = scorm_optionals_data($item,$standarddatas)) {
$data = new stdClass();
$data->scoid = $id;
foreach ($optionaldatas as $optionaldata) {
if (isset($item->$optionaldata)) {
$data->name = $optionaldata;
$data->value = $item->$optionaldata;
$dataid = $DB->insert_record('scorm_scoes_data',$data);
}
if (isset($item->sequencingrules)) {
foreach($item->sequencingrules as $sequencingrule) {
$rule = new stdClass();
$rule->scoid = $id;
$rule->ruletype = $sequencingrule->type;
$rule->conditioncombination = $sequencingrule->conditioncombination;
$rule->action = $sequencingrule->action;
$ruleid = $DB->insert_record('scorm_seq_ruleconds',$rule);
if (isset($sequencingrule->ruleconditions)) {
foreach($sequencingrule->ruleconditions as $rulecondition) {
$rulecond = new stdClass();
$rulecond->scoid = $id;
$rulecond->ruleconditionsid = $ruleid;
$rulecond->referencedobjective = $rulecondition->referencedobjective;
$rulecond->measurethreshold = $rulecondition->measurethreshold;
$rulecond->cond = $rulecondition->cond;
$rulecondid = $DB->insert_record('scorm_seq_rulecond',$rulecond);
}
}
}
}
}
if (isset($item->rolluprules)) {
foreach($item->rolluprules as $rolluprule) {
$rollup = new stdClass();
$rollup->scoid = $id;
$rollup->childactivityset = $rolluprule->childactivityset;
$rollup->minimumcount = $rolluprule->minimumcount;
$rollup->minimumpercent = $rolluprule->minimumpercent;
$rollup->rollupruleaction = $rolluprule->rollupruleaction;
$rollup->conditioncombination = $rolluprule->conditioncombination;
if (isset($item->sequencingrules)) {
foreach($item->sequencingrules as $sequencingrule) {
$rule = new stdClass();
$rule->scoid = $id;
$rule->ruletype = $sequencingrule->type;
$rule->conditioncombination = $sequencingrule->conditioncombination;
$rule->action = $sequencingrule->action;
$ruleid = $DB->insert_record('scorm_seq_ruleconds',$rule);
if (isset($sequencingrule->ruleconditions)) {
foreach($sequencingrule->ruleconditions as $rulecondition) {
$rulecond = new stdClass();
$rulecond->scoid = $id;
$rulecond->ruleconditionsid = $ruleid;
$rulecond->referencedobjective = $rulecondition->referencedobjective;
$rulecond->measurethreshold = $rulecondition->measurethreshold;
$rulecond->cond = $rulecondition->cond;
$rulecondid = $DB->insert_record('scorm_seq_rulecond',$rulecond);
}
$rollupruleid = $DB->insert_record('scorm_seq_rolluprule',$rollup);
if (isset($rollup->conditions)) {
foreach($rollup->conditions as $condition){
$cond = new stdClass();
$cond->scoid = $rollup->scoid;
$cond->rollupruleid = $rollupruleid;
$cond->operator = $condition->operator;
$cond->cond = $condition->cond;
$conditionid = $DB->insert_record('scorm_seq_rolluprulecond',$cond);
}
}
}
if (isset($item->rolluprules)) {
foreach($item->rolluprules as $rolluprule) {
$rollup = new stdClass();
$rollup->scoid = $id;
$rollup->childactivityset = $rolluprule->childactivityset;
$rollup->minimumcount = $rolluprule->minimumcount;
$rollup->minimumpercent = $rolluprule->minimumpercent;
$rollup->rollupruleaction = $rolluprule->rollupruleaction;
$rollup->conditioncombination = $rolluprule->conditioncombination;
}
}
}
$rollupruleid = $DB->insert_record('scorm_seq_rolluprule',$rollup);
if (isset($rollup->conditions)) {
foreach($rollup->conditions as $condition){
$cond = new stdClass();
$cond->scoid = $rollup->scoid;
$cond->rollupruleid = $rollupruleid;
$cond->operator = $condition->operator;
$cond->cond = $condition->cond;
$conditionid = $DB->insert_record('scorm_seq_rolluprulecond',$cond);
}
}
}
}
if (isset($item->objectives)) {
foreach($item->objectives as $objective) {
$obj = new stdClass();
$obj->scoid = $id;
$obj->primaryobj = $objective->primaryobj;
$obj->satisfiedbumeasure = $objective->satisfiedbymeasure;
$obj->objectiveid = $objective->objectiveid;
$obj->minnormalizedmeasure = $objective->minnormalizedmeasure;
$objectiveid = $DB->insert_record('scorm_seq_objective',$obj);
if (isset($objective->mapinfos)) {
if (isset($item->objectives)) {
foreach($item->objectives as $objective) {
$obj = new stdClass();
$obj->scoid = $id;
$obj->primaryobj = $objective->primaryobj;
$obj->satisfiedbumeasure = $objective->satisfiedbymeasure;
$obj->objectiveid = $objective->objectiveid;
$obj->minnormalizedmeasure = $objective->minnormalizedmeasure;
$objectiveid = $DB->insert_record('scorm_seq_objective',$obj);
if (isset($objective->mapinfos)) {
//print_object($objective->mapinfos);
foreach($objective->mapinfos as $objmapinfo) {
$mapinfo = new stdClass();
$mapinfo->scoid = $id;
$mapinfo->objectiveid = $objectiveid;
$mapinfo->targetobjectiveid = $objmapinfo->targetobjectiveid;
$mapinfo->readsatisfiedstatus = $objmapinfo->readsatisfiedstatus;
$mapinfo->writesatisfiedstatus = $objmapinfo->writesatisfiedstatus;
$mapinfo->readnormalizedmeasure = $objmapinfo->readnormalizedmeasure;
$mapinfo->writenormalizedmeasure = $objmapinfo->writenormalizedmeasure;
$mapinfoid = $DB->insert_record('scorm_seq_mapinfo',$mapinfo);
}
foreach($objective->mapinfos as $objmapinfo) {
$mapinfo = new stdClass();
$mapinfo->scoid = $id;
$mapinfo->objectiveid = $objectiveid;
$mapinfo->targetobjectiveid = $objmapinfo->targetobjectiveid;
$mapinfo->readsatisfiedstatus = $objmapinfo->readsatisfiedstatus;
$mapinfo->writesatisfiedstatus = $objmapinfo->writesatisfiedstatus;
$mapinfo->readnormalizedmeasure = $objmapinfo->readnormalizedmeasure;
$mapinfo->writenormalizedmeasure = $objmapinfo->writenormalizedmeasure;
$mapinfoid = $DB->insert_record('scorm_seq_mapinfo',$mapinfo);
}
}
}
}
//print_object($item);
if (($launch == 0) && ((empty($scoes->defaultorg)) || ($scoes->defaultorg == $identifier))) {
$launch = $id;
}
if (($launch == 0) && ((empty($scoes->defaultorg)) || ($scoes->defaultorg == $identifier))) {
$launch = $id;
}
}
}
if (!empty($olditems)) {
foreach($olditems as $olditem) {
$DB->delete_records('scorm_scoes', array('id'=>$olditem->id));
$DB->delete_records('scorm_scoes_data',array('scoid'=>$olditem->id));
if (isset($olditem->newid)) {
$DB->set_field('scorm_scoes_track', 'scoid', $olditem->newid, array('scoid' => $olditem->id));
}
$DB->delete_records('scorm_scoes_track',array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_objective', array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_mapinfo', array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_ruleconds', array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_rulecond', array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_rolluprule', array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_rolluprulecond', array('scoid'=>$olditem->id));
}
}
$DB->set_field('scorm','version',$scoes->version, array('id'=>$scormid));
}
}
if (!empty($olditems)) {
foreach($olditems as $olditem) {
$DB->delete_records('scorm_scoes', array('id'=>$olditem->id));
$DB->delete_records('scorm_scoes_data',array('scoid'=>$olditem->id));
if (isset($olditem->newid)) {
$DB->set_field('scorm_scoes_track', 'scoid', $olditem->newid, array('scoid' => $olditem->id));
}
$DB->delete_records('scorm_scoes_track',array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_objective', array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_mapinfo', array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_ruleconds', array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_rulecond', array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_rolluprule', array('scoid'=>$olditem->id));
$DB->delete_records('scorm_seq_rolluprulecond', array('scoid'=>$olditem->id));
}
}
$scorm->version = $scoes->version;
}
return $launch;
$scorm->launch = $launch;
return true;
}
function scorm_optionals_data($item, $standarddata) {

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/scorm/db" VERSION="20070124" COMMENT="XMLDB file for Moodle mod/scorm"
<XMLDB PATH="mod/scorm/db" VERSION="20080903" COMMENT="XMLDB file for Moodle mod/scorm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
@ -8,17 +8,20 @@
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" ENUM="false" NEXT="course"/>
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="id" NEXT="name"/>
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="course" NEXT="reference"/>
<FIELD NAME="reference" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="name" NEXT="summary"/>
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="course" NEXT="scormtype"/>
<FIELD NAME="scormtype" TYPE="char" LENGTH="50" NOTNULL="true" DEFAULT="local" SEQUENCE="false" ENUM="false" COMMENT="local, external or repository" PREVIOUS="name" NEXT="reference"/>
<FIELD NAME="reference" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="scormtype" NEXT="summary"/>
<FIELD NAME="summary" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="reference" NEXT="version"/>
<FIELD NAME="version" TYPE="char" LENGTH="9" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="summary" NEXT="maxgrade"/>
<FIELD NAME="maxgrade" TYPE="float" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="version" NEXT="grademethod"/>
<FIELD NAME="grademethod" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="maxgrade" NEXT="whatgrade"/>
<FIELD NAME="whatgrade" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="grademethod" NEXT="maxattempt"/>
<FIELD NAME="maxattempt" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" ENUM="false" PREVIOUS="whatgrade" NEXT="updatefreq"/>
<FIELD NAME="updatefreq" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Define when the package must be automatically update" PREVIOUS="maxattempt" NEXT="md5hash"/>
<FIELD NAME="md5hash" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" ENUM="false" COMMENT="MD5 Hash of package file" PREVIOUS="updatefreq" NEXT="launch"/>
<FIELD NAME="launch" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="md5hash" NEXT="skipview"/>
<FIELD NAME="updatefreq" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Define when the package must be automatically update" PREVIOUS="maxattempt" NEXT="sha1hash"/>
<FIELD NAME="sha1hash" TYPE="char" LENGTH="40" NOTNULL="false" SEQUENCE="false" ENUM="false" COMMENT="pacakge content or ext path hash" PREVIOUS="updatefreq" NEXT="md5hash"/>
<FIELD NAME="md5hash" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" ENUM="false" COMMENT="MD5 Hash of package file" PREVIOUS="sha1hash" NEXT="revision"/>
<FIELD NAME="revision" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="revison number" PREVIOUS="md5hash" NEXT="launch"/>
<FIELD NAME="launch" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="revision" NEXT="skipview"/>
<FIELD NAME="skipview" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" ENUM="false" PREVIOUS="launch" NEXT="hidebrowse"/>
<FIELD NAME="hidebrowse" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="skipview" NEXT="hidetoc"/>
<FIELD NAME="hidetoc" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="hidebrowse" NEXT="hidenav"/>
@ -31,7 +34,7 @@
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="height"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
@ -194,4 +197,4 @@
</SENTENCES>
</STATEMENT>
</STATEMENTS>
</XMLDB>
</XMLDB>

View File

@ -1,6 +1,6 @@
<?php //$Id$
// This file keeps track of upgrades to
// This file keeps track of upgrades to
// the scorm module
//
// Sometimes, changes between versions involve
@ -33,15 +33,207 @@ function xmldb_scorm_upgrade($oldversion) {
$table = new xmldb_table('scorm');
$field = new xmldb_field('whatgrade');
$field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'grademethod');
/// Launch add field whatgrade
if (!$dbman->field_exists($table,$field)) {
$dbman->add_field($table, $field);
}
upgrade_mod_savepoint($result, 2008073000, 'scorm');
}
if ($result && $oldversion < 2008082500) {
/// Define field scormtype to be added to scorm
$table = new xmldb_table('scorm');
$field = new xmldb_field('scormtype', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL, null, null, null, 'local', 'name');
/// Launch add field scormtype
$dbman->add_field($table, $field);
/// scorm savepoint reached
upgrade_mod_savepoint($result, 2008082500, 'scorm');
}
if ($result && $oldversion < 2008090300) {
/// Define field sha1hash to be added to scorm
$table = new xmldb_table('scorm');
$field = new xmldb_field('sha1hash', XMLDB_TYPE_CHAR, '40', null, null, null, null, null, null, 'updatefreq');
/// Launch add field sha1hash
$dbman->add_field($table, $field);
/// scorm savepoint reached
upgrade_mod_savepoint($result, 2008090300, 'scorm');
}
if ($result && $oldversion < 2008090301) {
/// Define field revision to be added to scorm
$table = new xmldb_table('scorm');
$field = new xmldb_field('revision', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'md5hash');
/// Launch add field revision
$dbman->add_field($table, $field);
/// scorm savepoint reached
upgrade_mod_savepoint($result, 2008090301, 'scorm');
}
if ($result && $oldversion < 2008090302) {
$sql = "UPDATE {scorm}
SET scormtype = 'external'
WHERE reference LIKE ? OR reference LIKE ? OR reference LIKE ?";
$DB->execute($sql, array('http://%imsmanifest.xml', 'https://%imsmanifest.xml', 'www.%imsmanifest.xml'));
$sql = "UPDATE {scorm}
SET scormtype = 'localsync'
WHERE reference LIKE ? OR reference LIKE ? OR reference LIKE ?
OR reference LIKE ? OR reference LIKE ? OR reference LIKE ?";
$DB->execute($sql, array('http://%.zip', 'https://%.zip', 'www.%.zip', 'http://%.pif', 'https://%.pif', 'www.%.pif'));
$sql = "UPDATE {scorm} SET scormtype = 'imsrepository' WHERE reference LIKE ?";
$DB->execute($sql, array('#%'));
/// scorm savepoint reached
upgrade_mod_savepoint($result, 2008090302, 'scorm');
}
if ($result && $oldversion < 2008090303) {
//remove obsoleted config settings
unset_config('scorm_advancedsettings');
unset_config('scorm_windowsettings');
/// scorm savepoint reached
upgrade_mod_savepoint($result, 2008090303, 'scorm');
}
if ($result && $oldversion < 2008090304) {
/////////////////////////////////////
/// new file storage upgrade code ///
/////////////////////////////////////
function scorm_migrate_content_files($context, $base, $path) {
global $CFG;
$fullpathname = $base.$path;
$fs = get_file_storage();
$filearea = 'scorm_content';
$items = new DirectoryIterator($fullpathname);
foreach ($items as $item) {
if ($item->isDot()) {
unset($item); // release file handle
continue;
}
if ($item->isLink()) {
// do not follow symlinks - they were never supported in moddata, sorry
unset($item); // release file handle
continue;
}
if ($item->isFile()) {
if (!$item->isReadable()) {
notify(" File not readable, skipping: ".$fullpathname.$item->getFilename());
unset($item); // release file handle
continue;
}
$filepath = clean_param($path, PARAM_PATH);
$filename = clean_param($item->getFilename(), PARAM_FILE);
$oldpathname = $fullpathname.$item->getFilename();
if ($filename === '') {
continue;
unset($item); // release file handle
}
if (!$fs->file_exists($context->id, $filearea, '0', $filepath, $filename)) {
$file_record = array('contextid'=>$context->id, 'filearea'=>$filearea, 'itemid'=>0, 'filepath'=>$filepath, 'filename'=>$filename,
'timecreated'=>$item->getCTime(), 'timemodified'=>$item->getMTime());
unset($item); // release file handle
if ($fs->create_file_from_pathname($file_record, $oldpathname)) {
@unlink($oldpathname);
}
} else {
unset($item); // release file handle
}
} else {
//migrate recursively all subdirectories
$oldpathname = $fullpathname.$item->getFilename().'/';
$subpath = $path.$item->getFilename().'/';
unset($item); // release file handle
scorm_migrate_content_files($context, $base, $subpath);
@rmdir($oldpathname); // deletes dir if empty
}
}
unset($items); //release file handles
}
$fs = get_file_storage();
$sqlfrom = "FROM {scorm} s
JOIN {modules} m ON m.name = 'scorm'
JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = s.id)";
$count = $DB->count_records_sql("SELECT COUNT('x') $sqlfrom");
if ($rs = $DB->get_recordset_sql("SELECT s.id, s.scormtype, s.reference, s.course, cm.id AS cmid $sqlfrom ORDER BY s.course, s.id")) {
$pbar = new progress_bar('migratescormfiles', 500, true);
$olddebug = $DB->get_debug();
$DB->set_debug(false); // lower debug level, there might be many files
$i = 0;
foreach ($rs as $scorm) {
$i++;
upgrade_set_timeout(180); // set up timeout, may also abort execution
$pbar->update($i, $count, "Migrating scorm files - $i/$count.");
$context = get_context_instance(CONTEXT_MODULE, $scorm->cmid);
$coursecontext = get_context_instance(CONTEXT_COURSE, $scorm->course);
// first copy local packages if found - do not delete in case they are shared ;-)
if ($scorm->scormtype === 'local' and preg_match('/.*(\.zip|\.pif)$/i', $scorm->reference)) {
$packagefile = '/'.clean_param($scorm->reference, PARAM_PATH);
$pathnamehash = sha1($coursecontext->id.'course_content0'.$packagefile);
if ($file = $fs->get_file_by_hash($pathnamehash)) {
$file_record = array('scontextid'=>$context->id, 'filearea'=>'scorm_pacakge',
'itemid'=>0, 'filepath'=>'/');
$packagefile = $fs->create_file_from_storedfile($file_record, $file);
$scorm->reference = $packagefile->get_filename();
} else {
$scorm->reference = '';
}
$DB->update_record('scorm', $scorm);
}
// now migrate the extracted package
$basepath = "$CFG->dataroot/$scorm->course/$CFG->moddata/scorm/$scorm->id";
if (!is_dir($basepath)) {
//no files?
continue;
}
scorm_migrate_content_files($context, $basepath, '/');
// remove dirs if empty
@rmdir("$CFG->dataroot/$scorm->course/$CFG->moddata/scorm/$scorm->id/");
@rmdir("$CFG->dataroot/$scorm->course/$CFG->moddata/scorm/");
@rmdir("$CFG->dataroot/$scorm->course/$CFG->moddata/");
}
$DB->set_debug($olddebug); // reset debug level
$rs->close();
}
/// scorm savepoint reached
upgrade_mod_savepoint($result, 2008090304, 'scorm');
}
return $result;
}

View File

@ -1,72 +1,93 @@
<?php // $Id$
define('SCORM_TYPE_LOCAL', 'local');
define('SCORM_TYPE_LOCALSYNC', 'localsync');
define('SCORM_TYPE_EXTERNAL', 'external');
define('SCORM_TYPE_IMSREPOSITORY', 'imsrepository');
/**
* Given an object containing all the necessary data,
* (defined by the form in mod_form.php) this function
* will create a new instance and return the id number
* of the new instance.
*
* @param mixed $scorm Form data
* @return int
* @param object $scorm Form data
* @param object $mform
* @return int new instance id
*/
//require_once('locallib.php');
function scorm_add_instance($scorm) {
function scorm_add_instance($scorm, $mform=null) {
global $CFG, $DB;
require_once('locallib.php');
if (($packagedata = scorm_check_package($scorm)) != null) {
$scorm->pkgtype = $packagedata->pkgtype;
$scorm->datadir = $packagedata->datadir;
$scorm->launch = $packagedata->launch;
$scorm->parse = 1;
$cmid = $scorm->coursemodule;
$cmidnumber = $scorm->cmidnumber;
$courseid = $scorm->course;
$scorm->timemodified = time();
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));
}
$context = get_context_instance(CONTEXT_MODULE, $cmid);
$scorm = scorm_option2text($scorm);
$scorm->width = str_replace('%','',$scorm->width);
$scorm->height = str_replace('%','',$scorm->height);
$scorm = scorm_option2text($scorm);
$scorm->width = (int)str_replace('%', '', $scorm->width);
$scorm->height = (int)str_replace('%', '', $scorm->height);
//sanitize submitted values a bit
$scorm->width = clean_param($scorm->width, PARAM_INT);
$scorm->height = clean_param($scorm->height, PARAM_INT);
if (!isset($scorm->whatgrade)) {
$scorm->whatgrade = 0;
}
$scorm->grademethod = ($scorm->whatgrade * 10) + $scorm->grademethod;
$id = $DB->insert_record('scorm', $scorm);
if (scorm_external_link($scorm->reference) || ((basename($scorm->reference) != 'imsmanifest.xml') && ($scorm->reference[0] != '#'))) {
// Rename temp scorm dir to scorm id
$scorm->dir = $CFG->dataroot.'/'.$scorm->course.'/moddata/scorm';
if (file_exists($scorm->dir.'/'.$id)) {
//delete directory as it shouldn't exist! - most likely there from an old moodle install with old files in dataroot
scorm_delete_files($scorm->dir.'/'.$id);
}
rename($scorm->dir.$scorm->datadir,$scorm->dir.'/'.$id);
}
// Parse scorm manifest
if ($scorm->parse == 1) {
$scorm->id = $id;
$scorm->launch = scorm_parse($scorm);
$DB->set_field('scorm', 'launch', $scorm->launch, array('id'=>$scorm->id));
}
scorm_grade_item_update($scorm);
return $id;
} else {
print_error('badpackage','scorm');
if (!isset($scorm->whatgrade)) {
$scorm->whatgrade = 0;
}
$scorm->grademethod = ($scorm->whatgrade * 10) + $scorm->grademethod;
if (!$id = $DB->insert_record('scorm', $scorm)) {
return false;
}
/// update course module record - from now on this instance properly exists and all function may be used
if (!$DB->set_field('course_modules', 'instance', $id, array('id'=>$cmid))) {
print_error('cannotaddcoursemodule');
}
/// reload scorm instance
$scorm = $DB->get_record('scorm', array('id'=>$id));
/// store the package and verify
if ($scorm->scormtype === SCORM_TYPE_LOCAL) {
if ($mform) {
$filename = $mform->get_new_filename('packagefile');
if ($filename !== false) {
$fs = get_file_storage();
$fs->delete_area_files($context->id, 'scorm_package');
$mform->save_stored_file('packagefile', $context->id, 'scorm_package', 0, '/', $filename);
$scorm->reference = $filename;
}
}
} else if ($scorm->scormtype === SCORM_TYPE_LOCALSYNC) {
$scorm->reference = $scorm->packageurl;
} else if ($scorm->scormtype === SCORM_TYPE_EXTERNAL) {
$scorm->reference = $scorm->packageurl;
} else if ($scorm->scormtype === SCORM_TYPE_IMSREPOSITORY) {
$scorm->reference = $scorm->packageurl;
} else {
return false;
}
// save reference
$DB->update_record('scorm', $scorm);
/// extra fields required in grade related functions
$scorm->course = $courseid;
$scorm->cmidnumber = $cmidnumber;
$scorm->cmid = $cmid;
scorm_parse($scorm, true);
scorm_grade_item_update($scorm);
return $scorm->id;
}
/**
@ -74,65 +95,73 @@ function scorm_add_instance($scorm) {
* (defined by the form in mod_form.php) this function
* will update an existing instance with new data.
*
* @param mixed $scorm Form data
* @return int
* @param object $scorm Form data
* @param object $mform
* @return bool success
*/
function scorm_update_instance($scorm) {
function scorm_update_instance($scorm, $mform=null) {
global $CFG, $DB;
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->reference[0] != '#') { //dont set md5hash if this is from a repo.
$scorm->md5hash = md5_file($CFG->dataroot.'/'.$scorm->course.'/'.$scorm->reference);
} elseif($scorm->reference[0] != '#') { //dont set md5hash if this is from a repo.
$scorm->dir = $CFG->dataroot.'/'.$scorm->course.'/moddata/scorm';
$scorm->md5hash = md5_file($scorm->dir.$scorm->datadir.'/'.basename($scorm->reference));
}
}
}
$cmid = $scorm->coursemodule;
$cmidnumber = $scorm->cmidnumber;
$courseid = $scorm->course;
$scorm->timemodified = time();
$scorm->id = $scorm->instance;
$context = get_context_instance(CONTEXT_MODULE, $cmid);
if ($scorm->scormtype === SCORM_TYPE_LOCAL) {
if ($mform) {
$filename = $mform->get_new_filename('packagefile');
if ($filename !== false) {
$scorm->reference = $filename;
$fs = get_file_storage();
$fs->delete_area_files($context->id, 'scorm_package');
$mform->save_stored_file('packagefile', $context->id, 'scorm_package', 0, '/', $filename);
}
}
} else if ($scorm->scormtype === SCORM_TYPE_LOCALSYNC) {
$scorm->reference = $scorm->packageurl;
} else if ($scorm->scormtype === SCORM_TYPE_EXTERNAL) {
$scorm->reference = $scorm->packageurl;
} else if ($scorm->scormtype === SCORM_TYPE_IMSREPOSITORY) {
$scorm->reference = $scorm->packageurl;
} else {
return false;
}
$scorm = scorm_option2text($scorm);
$scorm->width = str_replace('%','',$scorm->width);
$scorm->height = str_replace('%','',$scorm->height);
$scorm->width = (int)str_replace('%','',$scorm->width);
$scorm->height = (int)str_replace('%','',$scorm->height);
$scorm->timemodified = time();
if (!isset($scorm->whatgrade)) {
$scorm->whatgrade = 0;
}
$scorm->grademethod = ($scorm->whatgrade * 10) + $scorm->grademethod;
$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 = $DB->get_record('scorm', array('id'=>$scorm->id));
$scorm->reference = $oldscorm->reference; // This fix a problem with Firefox when the teacher choose Cancel on overwrite question
}
if ($result = $DB->update_record('scorm', $scorm)) {
scorm_grade_item_update(stripslashes_recursive($scorm));
//scorm_grade_item_update($scorm); // John Macklins fix - dont think this is needed
if (!$DB->update_record('scorm', $scorm)) {
return false;
}
return $result;
$scorm = $DB->get_record('scorm', array('id'=>$scorm->id));
/// extra fields required in grade related functions
$scorm->course = $courseid;
$scorm->idnumber = $cmidnumber;
$scorm->cmid = $cmid;
scorm_parse($scorm, (bool)$scorm->updatefreq);
scorm_grade_item_update($scorm);
return true;
}
/**
@ -152,13 +181,6 @@ function scorm_delete_instance($id) {
$result = true;
$scorm->dir = $CFG->dataroot.'/'.$scorm->course.'/moddata/scorm';
if (is_dir($scorm->dir.'/'.$scorm->id)) {
// Delete any dependent files
require_once('locallib.php');
scorm_delete_files($scorm->dir.'/'.$scorm->id);
}
// Delete any dependent records
if (! $DB->delete_records('scorm_scoes_track', array('scormid'=>$scorm->id))) {
$result = false;
@ -168,7 +190,7 @@ function scorm_delete_instance($id) {
if (! $DB->delete_records('scorm_scoes_data', array('scoid'=>$sco->id))) {
$result = false;
}
}
}
$DB->delete_records('scorm_scoes', array('scorm'=>$scorm->id));
} else {
$result = false;
@ -197,10 +219,10 @@ function scorm_delete_instance($id) {
}
if (! $DB->delete_records('scorm_sequencing_ruleconditions', array('scormid'=>$scorm->id))) {
$result = false;
}*/
}*/
scorm_grade_item_delete($scorm);
return $result;
}
@ -211,11 +233,11 @@ function scorm_delete_instance($id) {
*
* @param int $course Course id
* @param int $user User id
* @param int $mod
* @param int $mod
* @param int $scorm The scorm id
* @return mixed
*/
function scorm_user_outline($course, $user, $mod, $scorm) {
function scorm_user_outline($course, $user, $mod, $scorm) {
global $CFG;
require_once('locallib.php');
@ -230,7 +252,7 @@ function scorm_user_outline($course, $user, $mod, $scorm) {
*
* @param int $course Course id
* @param int $user User id
* @param int $mod
* @param int $mod
* @param int $scorm The scorm id
* @return boolean
*/
@ -244,7 +266,7 @@ function scorm_user_complete($course, $user, $mod, $scorm) {
$lastmodify = 0;
$sometoreport = false;
$report = '';
if ($orgs = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id, 'organization'=>'', 'launch'=>''),'id','id,identifier,title')) {
if (count($orgs) <= 1) {
unset($orgs);
@ -263,7 +285,7 @@ function scorm_user_complete($course, $user, $mod, $scorm) {
$conditions['scorm'] = $scorm->id;
if ($scoes = $DB->get_records('scorm_scoes', $conditions, "id ASC")){
// drop keys so that we can access array sequentially
$scoes = array_values($scoes);
$scoes = array_values($scoes);
$level=0;
$sublist=1;
$parents[$level]='/';
@ -336,7 +358,7 @@ function scorm_user_complete($course, $user, $mod, $scorm) {
}
}
$report .= "\t\t\t</ul></li>\n";
}
}
} else {
$report .= "&nbsp;$sco->title</li>\n";
}
@ -380,7 +402,8 @@ function scorm_cron () {
require_once('locallib.php');
$sitetimezone = $CFG->timezone;
/// Now see if there are any digest mails waiting to be sent, and if we should send them
/// Now see if there are any scorm updates to be done
if (!isset($CFG->scorm_updatetimelast)) { // To catch the first time
set_config('scorm_updatetimelast', 0);
}
@ -395,11 +418,8 @@ function scorm_cron () {
mtrace('Updating scorm packages which require daily update');//We are updating
$scormsupdate = $DB->get_records('scorm', array('updatefreq'=>UPDATE_EVERYDAY));
if (!empty($scormsupdate)) {
foreach($scormsupdate as $scormupdate) {
$scormupdate->instance = $scormupdate->id;
$id = scorm_update_instance($scormupdate);
}
foreach($scormsupdate as $scormupdate) {
scorm_parse($scormupdate, true);
}
}
@ -514,7 +534,7 @@ function scorm_grade_item_update($scorm, $grades=NULL) {
if (isset($scorm->cmidnumber)) {
$params['idnumber'] = $scorm->cmidnumber;
}
if (($scorm->grademethod % 10) == 0) { // GRADESCOES
if ($maxgrade = $DB->count_records_select('scorm_scoes', 'scorm = ? AND launch <> ?', array($scorm->id, $DB->sql_empty()))) {
$params['gradetype'] = GRADE_TYPE_VALUE;
@ -559,7 +579,14 @@ function scorm_get_post_actions() {
}
function scorm_option2text($scorm) {
global $SCORM_POPUP_OPTIONS;
$SCORM_POPUP_OPTIONS = array('resizable'=>1,
'scrollbars'=>1,
'directories'=>0,
'location'=>0,
'menubar'=>0,
'toolbar'=>0,
'status'=>0);
if (isset($scorm->popup)) {
if ($scorm->popup == 1) {
$optionlist = array();
@ -569,11 +596,11 @@ function scorm_option2text($scorm) {
} else {
$optionlist[] = $name.'=0';
}
}
}
$scorm->options = implode(',', $optionlist);
} else {
$scorm->options = '';
}
}
} else {
$scorm->popup = 0;
$scorm->options = '';
@ -656,4 +683,131 @@ function scorm_get_extra_capabilities() {
return array('moodle/site:accessallgroups');
}
/**
* Lists all file areas current user may browse
*/
function scorm_get_file_areas($course, $cm, $context) {
$areas = array();
if (has_capability('moodle/course:managefiles', $context)) {
$areas['scorm_intro'] = get_string('areaintro', 'scorm');
$areas['scorm_content'] = get_string('areacontent', 'scorm');
$areas['scorm_package'] = get_string('areapackage', 'scorm');
}
return $areas;
}
/**
* File browsing support
*/
function scorm_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
global $CFG;
if (!has_capability('moodle/course:managefiles', $context)) {
return null;
}
// no writing for now!
$fs = get_file_storage();
if ($filearea === 'scorm_content') {
$filepath = is_null($filepath) ? '/' : $filepath;
$filename = is_null($filename) ? '.' : $filename;
$urlbase = $CFG->wwwroot.'/pluginfile.php';
if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
if ($filepath === '/' and $filename === '.') {
$storedfile = new virtual_root_file($context->id, $filearea, 0);
} else {
// not found
return null;
}
}
class scorm_package_file_info extends file_info_stored {
public function get_parent() {
if ($this->lf->get_filepath() === '/' and $this->lf->get_filename() === '.') {
return $this->browser->get_file_info($this->context);
}
return parent::get_parent();
}
public function get_visible_name() {
if ($this->lf->get_filepath() === '/' and $this->lf->get_filename() === '.') {
return $this->areavisiblename;
}
return parent::get_visible_name();
}
}
return new scorm_package_file_info($browser, $context, $storedfile, $urlbase, $areas[$filearea], true, true, false);
} else if ($filearea === 'scorm_package') {
$filepath = is_null($filepath) ? '/' : $filepath;
$filename = is_null($filename) ? '.' : $filename;
$urlbase = $CFG->wwwroot.'/pluginfile.php';
if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
if ($filepath === '/' and $filename === '.') {
$storedfile = new virtual_root_file($context->id, $filearea, 0);
} else {
// not found
return null;
}
}
return new file_info_stored($browser, $context, $storedfile, $urlbase, $areas[$filearea], false, true, false);
}
// scorm_intro handled in file_browser
return false;
}
/**
* Serves scorm content, introduction images and packages. Implements needed access control ;-)
*/
function scorm_pluginfile($course, $cminfo, $context, $filearea, $args) {
global $CFG;
if (!$cminfo->uservisible) {
return false; // probably hidden
}
$lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
if ($filearea === 'scorm_intro') {
// all users may access it
$relativepath = '/'.implode('/', $args);
$fullpath = $context->id.'scorm_intro0'.$relativepath;
$fs = get_file_storage();
if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
return false;
}
} else if ($filearea === 'scorm_content') {
$revision = (int)array_shift($args); // prevents caching problems - ignored here
$relativepath = '/'.implode('/', $args);
$fullpath = $context->id.'scorm_content0'.$relativepath;
// TODO: add any other access restrictions here if needed!
} else if ($filearea === 'scorm_package') {
if (!has_capability('moodle/course:manageactivities', $context)) {
return false;
}
$relativepath = '/'.implode('/', $args);
$fullpath = $context->id.'scorm_package0'.$relativepath;
$lifetime = 0; // no caching here
} else {
return false;
}
$fs = get_file_storage();
if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
return false;
}
// finally send the file
send_stored_file($file, $lifetime, 0, false);
}
?>

View File

@ -2,8 +2,8 @@
require_once('../../config.php');
require_once('locallib.php');
$id = optional_param('id', '', PARAM_INT); // Course Module ID, or
$a = optional_param('a', '', PARAM_INT); // scorm ID
$id = optional_param('id', '', PARAM_INT); // Course Module ID, or
$a = optional_param('a', '', PARAM_INT); // scorm ID
$scoid = required_param('scoid', PARAM_INT); // sco ID
$delayseconds = 2; // Delay time before sco launch, used to give time to browser to define API
@ -33,6 +33,9 @@
}
require_login($course->id, false, $cm);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
if (!empty($scoid)) {
//
// Direct SCO request
@ -60,7 +63,7 @@
$value = 'completed';
$result = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
}
//
// Forge SCO URL
//
@ -76,7 +79,7 @@
$sco->parameters = substr($sco->parameters,1);
}
}
if ($version == 'AICC') {
if (isset($sco->parameters) && (!empty($sco->parameters))) {
$sco->parameters = '&'. $sco->parameters;
@ -89,31 +92,26 @@
$launcher = $sco->launch;
}
}
if (scorm_external_link($sco->launch)) {
// Remote learning activity
//TODO: does this happen?
$result = $launcher;
} else if ($scorm->reference[0] == '#') {
} 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 ((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;
}
$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
$result = "$CFG->wwwroot/pluginfile.php/$context->id/scorm_content/$scorm->revision/$launcher";
}
$scormpixdir = $CFG->modpixpath.'/scorm/pix';
?>
<html>
@ -134,11 +132,11 @@
}
}, 1000);
}
//]]>
//]]>
</script>
<noscript>
<meta http-equiv="refresh" content="<?php echo $delayseconds ?>;url=<?php echo $result ?>" />
</noscript>
</noscript>
</head>
<body onload="doredirect();">
<p><?php echo get_string('activityloading', 'scorm');?> <span id="countdown"><?php echo $delayseconds ?></span> <?php echo get_string('numseconds');?>. &nbsp; <img src='<?php echo $scormpixdir;?>/wait.gif'><p>
@ -146,5 +144,5 @@
add_to_log($course->id, 'scorm', 'launch', 'view.php?id='.$cm->id, $result, $cm->id);
}
?>
</body>
</body>
</html>

View File

@ -1,5 +1,7 @@
<?php // $Id$
require_once("$CFG->dirroot/mod/scorm/lib.php");
/// Constants and settings for module scorm
define('UPDATE_NEVER', '0');
define('UPDATE_ONCHANGE', '1');
@ -14,122 +16,129 @@ define('GRADESCOES', '0');
define('GRADEHIGHEST', '1');
define('GRADEAVERAGE', '2');
define('GRADESUM', '3');
$SCORM_GRADE_METHOD = array (GRADESCOES => get_string('gradescoes', 'scorm'),
GRADEHIGHEST => get_string('gradehighest', 'scorm'),
GRADEAVERAGE => get_string('gradeaverage', 'scorm'),
GRADESUM => get_string('gradesum', 'scorm'));
define('HIGHESTATTEMPT', '0');
define('AVERAGEATTEMPT', '1');
define('FIRSTATTEMPT', '2');
define('LASTATTEMPT', '3');
$SCORM_WHAT_GRADE = array (HIGHESTATTEMPT => get_string('highestattempt', 'scorm'),
AVERAGEATTEMPT => get_string('averageattempt', 'scorm'),
FIRSTATTEMPT => get_string('firstattempt', 'scorm'),
LASTATTEMPT => get_string('lastattempt', 'scorm'));
$SCORM_POPUP_OPTIONS = array('resizable'=>1,
'scrollbars'=>1,
'directories'=>0,
'location'=>0,
'menubar'=>0,
'toolbar'=>0,
'status'=>0);
$stdoptions = '';
foreach ($SCORM_POPUP_OPTIONS as $popupopt => $value) {
$stdoptions .= $popupopt.'='.$value;
if ($popupopt != 'status') {
$stdoptions .= ',';
}
}
if (!isset($CFG->scorm_maxattempts)) {
set_config('scorm_maxattempts','6');
}
if (!isset($CFG->scorm_frameheight)) {
set_config('scorm_frameheight','500');
}
if (!isset($CFG->scorm_framewidth)) {
set_config('scorm_framewidth','100%');
}
if (!isset($CFG->scorm_updatetime)) {
set_config('scorm_updatetime','2');
}
if (!isset($CFG->scorm_advancedsettings)) {
set_config('scorm_advancedsettings','0');
}
if (!isset($CFG->scorm_windowsettings)) {
set_config('scorm_windowsettings','0');
}
/// Local Library of functions for module scorm
/**
* This function will permanently delete the given
* directory and all files and subdirectories.
*
* @param string $directory The directory to remove
* @return boolean
*/
function scorm_delete_files($directory) {
if (is_dir($directory)) {
$files=scandir($directory);
set_time_limit(0);
foreach($files as $file) {
if (($file != '.') && ($file != '..')) {
if (!is_dir($directory.'/'.$file)) {
unlink($directory.'/'.$file);
* 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;
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, '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, 'scorm_package');
$file_record = array('contextid'=>$context->id, 'filearea'=>'scorm_package', 'itemid'=>0, 'filepath'=>'/');
if ($packagefile = $fs->create_file_from_url($file_record, $scorm->reference)) {
$newhash = sha1($scorm->reference);
} else {
scorm_delete_files($directory.'/'.$file);
$newhash = null;
}
}
}
rmdir($directory);
return true;
}
return false;
}
/**
* Create a new temporary subdirectory with a random name in the given path
*
* @param string $strpath The scorm data directory
* @return string/boolean
*/
function scorm_tempdir($strPath)
{
global $CFG;
if (is_dir($strPath)) {
do {
// Create a random string of 8 chars
$randstring = NULL;
$lchar = '';
$len = 8;
for ($i=0; $i<$len; $i++) {
$char = chr(rand(48,122));
while (!ereg('[a-zA-Z0-9]', $char)){
if ($char == $lchar) continue;
$char = chr(rand(48,90));
if ($packagefile) {
if (!$full and $packagefile and $scorm->sha1hash === $newhash) {
if (strpos($scorm->version, 'SCORM') !== false) {
if ($fs->get_file($context->id, 'scorm_content', 0, '/', 'imsmanifest.xml')) {
// no need to update
return;
}
$randstring .= $char;
$lchar = $char;
}
$datadir='/'.$randstring;
} while (file_exists($strPath.$datadir));
mkdir($strPath.$datadir, $CFG->directorypermissions);
@chmod($strPath.$datadir, $CFG->directorypermissions); // Just in case mkdir didn't do it
return $strPath.$datadir;
} 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, 'scorm_content');
$packer = get_file_packer('application/zip');
$packagefile->extract_to_storage($packer, $context->id, 'scorm_content', 0, '/');
} else if (!$full) {
return;
}
if ($manifest = $fs->get_file($context->id, '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';
}
}
} 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 {
return false;
// sorry, disabled type
return;
}
$scorm->revision++;
$scorm->sha1hash = $newhash;
$DB->update_record('scorm', $scorm);
}
function scorm_array_search($item, $needle, $haystacks, $strict=false) {
if (!empty($haystacks)) {
foreach ($haystacks as $key => $element) {
@ -189,7 +198,7 @@ function scorm_get_sco($id,$what=SCO_ALL) {
$sco->{$scodata->name} = $scodata->value;
}
} else if (($what != SCO_ONLY) && (!($scodatas = $DB->get_records('scorm_scoes_data', array('scoid'=>$id))))) {
$sco->parameters = '';
$sco->parameters = '';
}
return $sco;
} else {
@ -247,10 +256,10 @@ function scorm_insert_track($userid,$scormid,$scoid,$attempt,$element,$value) {
$track->timemodified = time();
$id = $DB->insert_record('scorm_scoes_track',$track);
}
// MDL-9552, update the gradebook everything raw score is sent
// Scoring by learning objects also needs to be included in the gradebook update
if (strstr($element, '.score.raw') ||
if (strstr($element, '.score.raw') ||
(($element == 'cmi.core.lesson_status' || $element == 'cmi.completion_status') && ($track->value == 'completed' || $track->value == 'passed'))) {
$scorm = $DB->get_record('scorm', array('id' => $scormid));
$grademethod = $scorm->grademethod % 10;
@ -259,7 +268,7 @@ function scorm_insert_track($userid,$scormid,$scoid,$attempt,$element,$value) {
scorm_update_grades($scorm, $userid);
}
}
return $id;
}
@ -276,7 +285,7 @@ function scorm_get_tracks($scoid,$userid,$attempt='') {
}
if ($tracks = $DB->get_records('scorm_scoes_track', array('userid'=>$userid, 'scoid'=>$scoid, 'attempt'=>$attempt),'element ASC')) {
$usertrack->userid = $userid;
$usertrack->scoid = $scoid;
$usertrack->scoid = $scoid;
// Defined in order to unify scorm1.2 and scorm2004
$usertrack->score_raw = '';
$usertrack->status = '';
@ -291,27 +300,27 @@ function scorm_get_tracks($scoid,$userid,$attempt='') {
case 'cmi.completion_status':
if ($track->value == 'not attempted') {
$track->value = 'notattempted';
}
}
$usertrack->status = $track->value;
break;
break;
case 'cmi.core.score.raw':
case 'cmi.score.raw':
$usertrack->score_raw = $track->value;
break;
break;
case 'cmi.core.session_time':
case 'cmi.session_time':
$usertrack->session_time = $track->value;
break;
break;
case 'cmi.core.total_time':
case 'cmi.total_time':
$usertrack->total_time = $track->value;
break;
}
break;
}
if (isset($track->timemodified) && ($track->timemodified > $usertrack->timemodified)) {
$usertrack->timemodified = $track->timemodified;
}
}
}
if (is_array($usertrack)) {
if (is_array($usertrack)) {
ksort($usertrack);
}
return $usertrack;
@ -330,13 +339,13 @@ function scorm_get_user_data($userid) {
function scorm_grade_user_attempt($scorm, $userid, $attempt=1, $time=false) {
global $DB;
$attemptscore = NULL;
$attemptscore = NULL;
$attemptscore->scoes = 0;
$attemptscore->values = 0;
$attemptscore->max = 0;
$attemptscore->sum = 0;
$attemptscore->lastmodify = 0;
if (!$scoes = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id))) {
return NULL;
}
@ -346,11 +355,11 @@ function scorm_grade_user_attempt($scorm, $userid, $attempt=1, $time=false) {
// and 1s are grademethod
$grademethod = $scorm->grademethod % 10;
foreach ($scoes as $sco) {
foreach ($scoes as $sco) {
if ($userdata=scorm_get_tracks($sco->id, $userid,$attempt)) {
if (($userdata->status == 'completed') || ($userdata->status == 'passed')) {
$attemptscore->scoes++;
}
}
if (!empty($userdata->score_raw)) {
$attemptscore->values++;
$attemptscore->sum += $userdata->score_raw;
@ -360,23 +369,23 @@ function scorm_grade_user_attempt($scorm, $userid, $attempt=1, $time=false) {
} else {
$attemptscore->lastmodify = 0;
}
}
}
}
}
}
switch ($grademethod) {
case GRADEHIGHEST:
$score = $attemptscore->max;
break;
break;
case GRADEAVERAGE:
if ($attemptscore->values > 0) {
$score = $attemptscore->sum/$attemptscore->values;
} else {
$score = 0;
}
break;
}
break;
case GRADESUM:
$score = $attemptscore->sum;
break;
break;
case GRADESCOES:
$score = $attemptscore->scoes;
break;
@ -410,7 +419,7 @@ function scorm_grade_user($scorm, $userid, $time=false) {
switch ($whatgrade) {
case FIRSTATTEMPT:
return scorm_grade_user_attempt($scorm, $userid, 1, $time);
break;
break;
case LASTATTEMPT:
return scorm_grade_user_attempt($scorm, $userid, scorm_get_last_attempt($scorm->id, $userid), $time);
break;
@ -502,7 +511,7 @@ function scorm_course_format_display($user,$course) {
echo '<div class="mod-scorm">';
if ($scorms = get_all_instances_in_course('scorm', $course)) {
// The module SCORM activity with the least id is the course
// The module SCORM activity with the least id is the course
$scorm = current($scorms);
if (! $cm = get_coursemodule_from_instance('scorm', $scorm->id, $course->id)) {
print_error('invalidcoursemodule');
@ -528,7 +537,7 @@ function scorm_course_format_display($user,$course) {
$headertext .= '<td class="reportlink">'.get_string('noreports','scorm');
}
$colspan = ' colspan="2"';
}
}
$headertext .= '</td></tr><tr><td'.$colspan.'>'.format_text(get_string('summary').':<br />'.$scorm->summary).'</td></tr></table>';
print_simple_box($headertext,'','100%');
scorm_view_display($user, $scorm, 'view.php?id='.$course->id, $cm, '100%');
@ -546,11 +555,8 @@ function scorm_course_format_display($user,$course) {
function scorm_view_display ($user, $scorm, $action, $cm, $boxwidth='') {
global $CFG, $DB;
if ($scorm->updatefreq == UPDATE_EVERYTIME){
require_once($CFG->dirroot.'/mod/scorm/lib.php');
$scorm->instance = $scorm->id;
scorm_update_instance($scorm);
if ($scorm->updatefreq == UPDATE_EVERYTIME) {
scorm_parse($scorm, false);
}
$organization = optional_param('organization', '', PARAM_INT);
@ -637,9 +643,9 @@ function scorm_simple_play($scorm,$user) {
global $DB;
$result = false;
$scoes = $DB->get_records_select('scorm_scoes', 'scorm = ? AND launch <> ?', array($scorm->id, $DB->sql_empty()));
if ($scoes && (count($scoes) == 1)) {
if ($scorm->skipview >= 1) {
$sco = current($scoes);
@ -675,356 +681,26 @@ function scorm_simple_play($scorm,$user) {
return $result;
}
*/
function scorm_parse($scorm) {
global $CFG;
if ($scorm->reference[0] == '#') {
if (isset($CFG->repositoryactivate) && $CFG->repositoryactivate) {
$referencedir = $CFG->repository.substr($scorm->reference,1);
}
} else {
if ((!scorm_external_link($scorm->reference)) && (basename($scorm->reference) == 'imsmanifest.xml')) {
$referencedir = $CFG->dataroot.'/'.$scorm->course.'/'.$scorm->datadir;
} else {
$referencedir = $CFG->dataroot.'/'.$scorm->course.'/moddata/scorm/'.$scorm->id;
}
}
// Parse scorm manifest
if ($scorm->pkgtype == 'AICC') {
require_once('datamodels/aicclib.php');
$scorm->launch = scorm_parse_aicc($referencedir, $scorm->id);
} else {
require_once('datamodels/scormlib.php');
$scorm->launch = scorm_parse_scorm($referencedir,$scorm->id);
}
return $scorm->launch;
}
/**
* Given a manifest path, this function will check if the manifest is valid
*
* @param string $manifest The manifest file
* @return object
*/
function scorm_validate_manifest($manifest) {
$validation = new stdClass();
if (is_file($manifest)) {
$validation->result = true;
} else {
$validation->result = false;
$validation->errors['reference'] = get_string('nomanifest','scorm');
}
return $validation;
}
/**
* Given a aicc package directory, this function will check if the course structure is valid
*
* @param string $packagedir The aicc package directory path
* @return object
*/
function scorm_validate_aicc($packagedir) {
$validation = new stdClass();
$validation->result = false;
if (is_dir($packagedir)) {
if ($handle = opendir($packagedir)) {
while (($file = readdir($handle)) !== false) {
$ext = substr($file,strrpos($file,'.'));
if (strtolower($ext) == '.cst') {
$validation->result = true;
break;
}
}
closedir($handle);
}
}
if ($validation->result == false) {
$validation->errors['reference'] = get_string('nomanifest','scorm');
}
return $validation;
}
function scorm_validate($data) {
global $CFG, $DB;
$validation = new stdClass();
$validation->errors = array();
if (!isset($data['course']) || empty($data['course'])) {
$validation->errors['reference'] = get_string('missingparam','scorm');
$validation->result = false;
return $validation;
}
$courseid = $data['course']; // Course Module ID
if (!isset($data['reference']) || empty($data['reference'])) {
$validation->errors['reference'] = get_string('packagefile','scorm');
$validation->result = false;
return $validation;
}
$reference = $data['reference']; // Package/manifest path/location
$scormid = $data['instance']; // scorm ID
$scorm = new stdClass();
if (!empty($scormid)) {
if (!$scorm = $DB->get_record('scorm', array('id'=>$scormid))) {
$validation->errors['reference'] = get_string('missingparam','scorm');
$validation->result = false;
return $validation;
}
}
if ($reference[0] == '#') {
if (isset($CFG->repositoryactivate) && $CFG->repositoryactivate) {
$reference = $CFG->repository.substr($reference,1).'/imsmanifest.xml';
} else {
$validation->errors['reference'] = get_string('badpackage','scorm');
$validation->result = false;
return $validation;
}
} else if (!scorm_external_link($reference)) {
$reference = $CFG->dataroot.'/'.$courseid.'/'.$reference;
}
// Create a temporary directory to unzip package or copy manifest and validate package
$tempdir = '';
$scormdir = '';
if ($scormdir = make_upload_directory("$courseid/$CFG->moddata/scorm")) {
if ($tempdir = scorm_tempdir($scormdir)) {
$localreference = $tempdir.'/'.basename($reference);
copy ("$reference", $localreference);
if (!is_file($localreference)) {
$validation->errors['reference'] = get_string('badpackage','scorm');
$validation->result = false;
} else {
$ext = strtolower(substr(basename($localreference),strrpos(basename($localreference),'.')));
switch ($ext) {
case '.pif':
case '.zip':
if (!unzip_file($localreference, $tempdir, false)) {
$validation->errors['reference'] = get_string('unziperror','scorm');
$validation->result = false;
} else {
unlink ($localreference);
if (is_file($tempdir.'/imsmanifest.xml')) {
$validation = scorm_validate_manifest($tempdir.'/imsmanifest.xml');
$validation->pkgtype = 'SCORM';
} else {
$validation = scorm_validate_aicc($tempdir);
if (($validation->result == 'regular') || ($validation->result == 'found')) {
$validation->pkgtype = 'AICC';
} else {
$validation->errors['reference'] = get_string('nomanifest','scorm');
$validation->result = false;
}
}
}
break;
case '.xml':
if (basename($localreference) == 'imsmanifest.xml') {
$validation = scorm_validate_manifest($localreference);
} else {
$validation->errors['reference'] = get_string('nomanifest','scorm');
$validation->result = false;
}
break;
default:
$validation->errors['reference'] = get_string('badpackage','scorm');
$validation->result = false;
break;
}
}
if (is_dir($tempdir)) {
// Delete files and temporary directory
scorm_delete_files($tempdir);
}
} else {
$validation->errors['reference'] = get_string('packagedir','scorm');
$validation->result = false;
}
} else {
$validation->errors['reference'] = get_string('datadir','scorm');
$validation->result = false;
}
return $validation;
}
function scorm_check_package($data) {
global $CFG, $COURSE, $DB;
$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)) {
copy ("$reference", $tempdir.'/'.basename($reference));
$mdcheck = md5_file($tempdir.'/'.basename($reference));
scorm_delete_files($tempdir);
}
}
}
if ($scorm = $DB->get_record('scorm', array('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)) {
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)) {
copy ("$reference", $tempdir.'/'.basename($reference));
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;
}
function scorm_get_count_users($scormid, $groupingid=null) {
global $CFG, $DB;
if (!empty($CFG->enablegroupings) && !empty($groupingid)) {
$sql = "SELECT COUNT(DISTINCT st.userid)
FROM {scorm_scoes_track} st
INNER JOIN {groups_members} gm ON st.userid = gm.userid
INNER JOIN {groupings_groups} gg ON gm.groupid = gg.groupid
INNER JOIN {groupings_groups} gg ON gm.groupid = gg.groupid
WHERE st.scormid = ? AND gg.groupingid = ?
";
$params = array($scormid, $groupingid);
} else {
$sql = "SELECT COUNT(DISTINCT st.userid)
FROM {scorm_scoes_track} st
FROM {scorm_scoes_track} st
WHERE st.scormid = ?
";
$params = array($scormid);
}
return ($DB->count_records_sql($sql, $params));
}

View File

@ -5,10 +5,22 @@ require_once($CFG->dirroot.'/mod/scorm/locallib.php');
class mod_scorm_mod_form extends moodleform_mod {
function definition() {
global $CFG;
global $CFG, $COURSE, $SCORM_GRADE_METHOD, $SCORM_WHAT_GRADE;
$mform =& $this->_form;
if (isset($CFG->slasharguments) && !$CFG->slasharguments) {
$mform = $this->_form;
$SCORM_GRADE_METHOD = array (GRADESCOES => get_string('gradescoes', 'scorm'),
GRADEHIGHEST => get_string('gradehighest', 'scorm'),
GRADEAVERAGE => get_string('gradeaverage', 'scorm'),
GRADESUM => get_string('gradesum', 'scorm'));
$SCORM_WHAT_GRADE = array (HIGHESTATTEMPT => get_string('highestattempt', 'scorm'),
AVERAGEATTEMPT => get_string('averageattempt', 'scorm'),
FIRSTATTEMPT => get_string('firstattempt', 'scorm'),
LASTATTEMPT => get_string('lastattempt', 'scorm'));
if (!$CFG->slasharguments) {
$mform->addElement('static', '', '',notify(get_string('slashargs', 'scorm'), 'notifyproblem', 'center', true));
}
//-------------------------------------------------------------------------------
@ -29,11 +41,34 @@ class mod_scorm_mod_form extends moodleform_mod {
$mform->addRule('summary', get_string('required'), 'required', null, 'client');
$mform->setHelpButton('summary', array('writing', 'questions', 'richtext'), false, 'editorhelpbutton');
// Scorm types
$options = array(SCORM_TYPE_LOCAL => get_string('typelocal', 'scorm'));
if ($CFG->scorm_allowtypeexternal) {
$options[SCORM_TYPE_EXTERNAL] = get_string('typeexternal', 'scorm');
}
if ($CFG->scorm_allowtypelocalsync) {
$options[SCORM_TYPE_LOCALSYNC] = get_string('typelocalsync', 'scorm');
}
if (!empty($CFG->repositoryactivate) and $CFG->scorm_allowtypeimsrepository) {
$options[SCORM_TYPE_IMSREPOSITORY] = get_string('typeimsrepository', 'scorm');
}
$mform->addElement('select', 'scormtype', get_string('scormtype', 'scorm'), $options);
// Reference
$mform->addElement('choosecoursefileorimsrepo', 'reference', get_string('package','scorm'));
$mform->setType('reference', PARAM_RAW); // We need to find a better PARAM
$mform->addRule('reference', get_string('required'), 'required');
$mform->setHelpButton('reference',array('package', get_string('package', 'scorm'), 'scorm'));
if (count($options) > 1) {
$mform->addElement('text', 'packageurl', get_string('url', 'scorm'), array('size'=>60));
$mform->setType('packageurl', PARAM_RAW);
$mform->setHelpButton('packageurl', array('packagefile', get_string('package', 'scorm'), 'scorm'));
$mform->disabledIf('packageurl', 'scormtype', 'eq', SCORM_TYPE_LOCAL);
}
// New local package upload
$mform->addElement('file', 'packagefile', get_string('package','scorm'));
$mform->disabledIf('packagefile', 'scormtype', 'noteq', SCORM_TYPE_LOCAL);
//-------------------------------------------------------------------------------
// Other Settings
@ -41,7 +76,7 @@ class mod_scorm_mod_form extends moodleform_mod {
// Grade Method
$mform->addElement('select', 'grademethod', get_string('grademethod', 'scorm'), $SCORM_GRADE_METHOD);
$mform->setHelpButton('grademethod', array('grademethod',get_string('grademethod', 'scorm'),'scorm'));
$mform->setHelpButton('grademethod', array('grademethod', get_string('grademethod', 'scorm'),'scorm'));
$mform->setDefault('grademethod', 0);
// Maximum Grade
@ -50,7 +85,7 @@ class mod_scorm_mod_form extends moodleform_mod {
}
$mform->addElement('select', 'maxgrade', get_string('maximumgrade'), $grades);
$mform->setDefault('maxgrade', 0);
$mform->disabledIf('maxgrade', 'grademethod','eq',GRADESCOES);
$mform->disabledIf('maxgrade', 'grademethod','eq', GRADESCOES);
// Attempts
$mform->addElement('static', '', '' ,'<hr />');
@ -99,12 +134,12 @@ class mod_scorm_mod_form extends moodleform_mod {
$mform->addElement('static', 'stagesize', get_string('stagesize','scorm'));
$mform->setHelpButton('stagesize', array('stagesize',get_string('stagesize', 'scorm'), 'scorm'));
// Width
$mform->addElement('text', 'width', get_string('width','scorm'),'maxlength="5" size="5"');
$mform->addElement('text', 'width', get_string('width','scorm'), 'maxlength="5" size="5"');
$mform->setDefault('width', $CFG->scorm_framewidth);
$mform->setType('width', PARAM_INT);
// Height
$mform->addElement('text', 'height', get_string('height','scorm'),'maxlength="5" size="5"');
$mform->addElement('text', 'height', get_string('height','scorm'), 'maxlength="5" size="5"');
$mform->setDefault('height', $CFG->scorm_frameheight);
$mform->setType('height', PARAM_INT);
@ -112,7 +147,7 @@ class mod_scorm_mod_form extends moodleform_mod {
$options = array();
$options[0] = get_string('iframe', 'scorm');
$options[1] = get_string('popup', 'scorm');
$mform->addElement('select', 'popup', get_string('display','scorm'), $options);
$mform->addElement('select', 'popup', get_string('display', 'scorm'), $options);
$mform->setDefault('popup', 0);
$mform->setAdvanced('popup');
@ -211,7 +246,7 @@ class mod_scorm_mod_form extends moodleform_mod {
foreach ($options as $option) {
list($element,$value) = explode('=',$option);
$element = trim($element);
$default_values[$element] = trim($value);
$default_values[$element] = trim($value);
}
}
if (isset($default_values['grademethod'])) {
@ -228,7 +263,7 @@ class mod_scorm_mod_form extends moodleform_mod {
$coursescorm = current($scorms);
if (($COURSE->format == 'scorm') && ((count($scorms) == 0) || ($default_values['instance'] == $coursescorm->id))) {
$default_values['redirect'] = 'yes';
$default_values['redirecturl'] = '../course/view.php?id='.$default_values['course'];
$default_values['redirecturl'] = '../course/view.php?id='.$default_values['course'];
} else {
$default_values['redirect'] = 'no';
$default_values['redirecturl'] = '../mod/scorm/view.php?id='.$default_values['coursemodule'];
@ -244,30 +279,88 @@ class mod_scorm_mod_form extends moodleform_mod {
function validation($data, $files) {
$errors = parent::validation($data, $files);
$validate = scorm_validate($data);
$type = $data['scormtype'];
if (!$validate->result) {
$errors = $errors + $validate->errors;
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;
}
//need to translate the "options" field.
//need to translate the "options" and "reference" field.
function set_data($default_values) {
if (is_object($default_values)) {
if (!empty($default_values->options)) {
$options = explode(',', $default_values->options);
foreach ($options as $option) {
$opt = explode('=', $option);
if (isset($opt[1])) {
$default_values->$opt[0] = $opt[1];
}
$default_values = (array)$default_values;
if (isset($default_values['scormtype']) and isset($default_values['reference'])) {
switch ($default_values['scormtype']) {
case SCORM_TYPE_LOCALSYNC :
case SCORM_TYPE_EXTERNAL:
case SCORM_TYPE_IMSREPOSITORY:
$default_values['packageurl'] = $default_values['reference'];
}
}
unset($default_values['reference']);
if (!empty($default_values['options'])) {
$options = explode(',', $default_values['options']);
foreach ($options as $option) {
$opt = explode('=', $option);
if (isset($opt[1])) {
$default_values[$opt][0] = $opt[1];
}
}
$default_values = (array)$default_values;
}
$this->data_preprocessing($default_values);
parent::set_data($default_values); //never slashed for moodleform_mod
parent::set_data($default_values);
}
}
?>

View File

@ -1,9 +1,25 @@
<?php //$Id$
$settings->add(new admin_setting_configtext('scorm_framewidth', get_string('width', 'scorm'),
get_string('framewidth', 'scorm'), '100%'));
get_string('framewidth', 'scorm'), 100));
$settings->add(new admin_setting_configtext('scorm_frameheight', get_string('height', 'scorm'),
get_string('frameheight', 'scorm'), 500));
?>
$settings->add(new admin_setting_configtext('scorm_maxattempts', get_string('maximumattempts', 'scorm'),
'', 6));
$settings->add(new admin_setting_configtext('scorm_updatetime', get_string('updatetime', 'scorm'),
'', 2));
$settings->add(new admin_setting_configcheckbox('scorm_allowtypeexternal', get_string('allowtypeexternal', 'scorm'),
'', 0));
$settings->add(new admin_setting_configcheckbox('scorm_allowtypelocalsync', get_string('allowtypelocalsync', 'scorm'),
'', 0));
$settings->add(new admin_setting_configcheckbox('scorm_allowtypeimsrepository', get_string('allowtypeimsrepository', 'scorm'),
'', 0));

View File

@ -6,12 +6,12 @@
/////////////////////////////////////////////////////////////////////////////////
// NOTE The version below was accidentally set a month into the future! We need to
// catch up now, so until 27th October please only increment in very tiny steps
// NOTE The version below was accidentally set a month into the future! We need to
// catch up now, so until 27th October please only increment in very tiny steps
// in HEAD, until we get past that date..
$module->version = 2008073100; // The (date) version of this module
$module->requires = 2007101509; // The version of Moodle that is required
$module->version = 2008090304; // The (date) version of this module
$module->requires = 2008090108; // The version of Moodle that is required
$module->cron = 300; // How often should cron check this module (seconds)?
?>