get_string("gradescoes", "scorm"), VALUEHIGHEST => get_string("gradehighest", "scorm"), VALUEAVERAGE => get_string("gradeaverage", "scorm"), VALUESUM => get_string("gradesum", "scorm")); if (!isset($CFG->scorm_validate)) { $scorm_validate = 'none'; //I've commented this out for Moodle 1.4, as I've seen errors in //SCORM packages even though the actual package worked fine. -- Martin Dougiamas if (extension_loaded('domxml') && version_compare(phpversion(),'5.0.0','<')) { $scorm_validate = 'domxml'; } if (version_compare(phpversion(),'5.0.0','>=')) { $scorm_validate = 'php5'; } set_config('scorm_validate', $scorm_validate); } function scorm_add_instance($scorm) { /// Given an object containing all the necessary data, /// (defined by the form in mod.html) this function /// will create a new instance and return the id number /// of the new instance. $scorm->timemodified = time(); # May have to add extra stuff in here # global $CFG; $id = insert_record('scorm', $scorm); // // Parse scorm manifest // if ($scorm->launch == 0) { $basedir = $CFG->dataroot."/".$scorm->course; $scormdir = "/moddata/scorm"; $scorm->launch = scorm_parse($basedir,$scormdir.$scorm->datadir."/imsmanifest.xml",$id); set_field("scorm","launch",$scorm->launch,"id",$id); } return $id; } function scorm_update_instance($scorm) { /// 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. $scorm->timemodified = time(); $scorm->id = $scorm->instance; # May have to add extra stuff in here # global $CFG; // // Check if scorm manifest needs to be reparsed // if ($scorm->launch == 0) { $basedir = $CFG->dataroot."/".$scorm->course; $scormdir = "/moddata/scorm"; $scorm->launch = scorm_parse($basedir,$scormdir.$scorm->datadir."/imsmanifest.xml",$scorm->id); } return update_record('scorm', $scorm); } function scorm_delete_instance($id) { /// Given an ID of an instance of this module, /// this function will permanently delete the instance /// and any data that depends on it. require('../config.php'); if (! $scorm = get_record('scorm', 'id', $id)) { return false; } $result = true; # Delete any dependent files # scorm_delete_files($CFG->dataroot.'/'.$scorm->course.'/moddata/scorm'.$scorm->datadir); # Delete any dependent records here # if (! delete_records('scorm_scoes_track', 'scormid', $scorm->id)) { $result = false; } if (! delete_records('scorm_scoes', 'scorm', $scorm->id)) { $result = false; } if (! delete_records('scorm', 'id', $scorm->id)) { $result = false; } return $result; } function scorm_user_outline($course, $user, $mod, $scorm) { /// Return a small object with summary information about what a /// user has done with a given particular instance of this module /// Used for user activity reports. /// $return->time = the time they did it /// $return->info = a short text description return true; // TO FIX } function scorm_user_complete($course, $user, $mod, $scorm) { /// Print a detailed representation of what a user has done with /// a given particular instance of this module, for user activity reports. return true; // TO FIX } function scorm_print_recent_activity(&$logs, $isteacher=false) { /// Given a list of logs, assumed to be those since the last login /// this function prints a short list of changes related to this module /// If isteacher is true then perhaps additional information is printed. /// This function is called from course/lib.php: print_recent_activity() return false; // True if anything was printed, otherwise false } function scorm_cron () { /// Function to be run periodically according to the moodle cron /// This function searches for things that need to be done, such /// as sending out mail, toggling flags etc ... global $CFG; return true; } function scorm_grades($scormid) { /// Must return an array of grades for a given instance of this module, /// indexed by user. It also returns a maximum allowed grade. global $CFG; if (!$scorm = get_record("scorm", "id", $scormid)) { return NULL; } if ($scorm->grademethod == VALUESCOES) { if (!$return->maxgrade = count_records_select('scorm_scoes',"scorm='$scormid' AND launch<>''")) { return NULL; } $return->grades = NULL; if ($sco_users=get_records_select('scorm_scoes_track', "scormid='$scormid' GROUP BY userid")) { foreach ($sco_users as $sco_user) { $user_data=get_records_select('scorm_scoes_track',"scormid='$scormid' AND userid='$sco_user->userid' AND element='cmi_core_lesson_status'"); $scores->completed=0; $scores->browsed=0; $scores->incomplete=0; $scores->failed=0; $scores->notattempted=0; $result=''; $data = current($user_data); foreach ($user_data as $data) { if ($data->value=='passed') $scores->completed++; else $scores->{scorm_remove_spaces($data->value)}++; } if ($scores->completed) $result.="wwwroot/mod/scorm/pix/completed.gif\" alt=\"".get_string('completed','scorm')."\" title=\"".get_string('completed','scorm')."\" /> $scores->completed "; if ($scores->incomplete) $result.="wwwroot/mod/scorm/pix/incomplete.gif\" alt=\"".get_string('incomplete','scorm')."\" title=\"".get_string('incomplete','scorm')."\" /> $scores->incomplete "; if ($scores->failed) $result.="wwwroot/mod/scorm/pix/failed.gif\" alt=\"".get_string('failed','scorm')."\" title=\"".get_string('failed','scorm')."\" /> $scores->failed "; if ($scores->browsed) $result.="wwwroot/mod/scorm/pix/browsed.gif\" alt=\"".get_string('browsed','scorm')."\" title=\"".get_string('browsed','scorm')."\" /> $scores->browsed "; if ($scores->notattempted) $result.="wwwroot/mod/scorm/pix/notattempted.gif\" alt=\"".get_string('notattempted','scorm')."\" title=\"".get_string('notattempted','scorm')."\" /> $scores->notattempted "; $return->grades[$sco_user->userid]=$result; } } } else { $grades = get_records_select("scorm_scoes_track", "scormid=$scormid AND element='cmi_core_score_raw' AND value<>''","","id,userid,value"); //$grades = get_records_menu("scorm_scoes_track", "scormid",$scormid,"","userid,cmi_core_score_raw"); $valutations = array(); foreach ($grades as $grade) { if (!isset($valutations[$grade->userid])) { if ($scorm->grademethod == VALUEAVERAGE) { $values = array(); $values[$grade->userid]->grade = 0; $values[$grade->userid]->values = 0; } $valutations[$grade->userid] = 0; } switch ($scorm->grademethod) { case VALUEHIGHEST: if ($grade->value > $valutations[$grade->userid]) { $valutations[$grade->userid] = $grade->value; } break; case VALUEAVERAGE: $values[$grade->userid]->grade += $grade->value; $values[$grade->userid]->values++; break; case VALUESUM: $valutations[$grade->userid] += $grade->value; break; } } if ($scorm->grademethod == VALUEAVERAGE) { foreach($values as $userid => $value) { $valutations[$userid] = $value->grade/$value->values; } } //print_r($grades); $return->grades = $valutations; $return->maxgrade = $scorm->maxgrade; } return $return; } ////////////////////////////////////////////////////////////////////////////////////// /// Any other scorm functions go here. Each of them must have a name that /// starts with scorm_ function scorm_randstring($len = '8') { $rstring = NULL; $lchar = ''; 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)); } $rstring .= $char; $lchar = $char; } return $rstring; } function scorm_datadir($strPath, $existingdir='', $prefix = 'SCORM') { global $CFG; if (($existingdir!='') && (is_dir($strPath.$existingdir))) return $strPath.$existingdir; if (is_dir($strPath)) { do { $datadir='/'.$prefix.scorm_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 { return false; } } if ($CFG->scorm_validate == 'domxml') { require_once('validatordomxml.php'); } function scorm_validate($manifest) { global $CFG; global $item_idref_array; global $idres_array; global $def_org_array; global $id_org_array; if (is_file ($manifest)) { if (file_exists($manifest)) { if ($CFG->scorm_validate == 'domxml') { $manifest_string = file_get_contents($manifest); /* Elimino i caratteri speciali di spaziatura e ritorno a capo dal file xml */ $spec = array('\n', '\r', '\t', '\0', '\x0B'); $content = str_replace($spec, '', $manifest_string); if ($xmldoc = domxml_open_mem($content)) { $root = $xmldoc->document_element(); if (!testRoot($root)) { return 'syntax'; } if (testNode($root)) { // Nel corpo di questo if si controllano le corrispondenze fra gli attributi // Nello Standard SCORM ad ogni attributo idRef di deve corrispondere // un attributo ID di // Gli array degli attributi sono stati dichiarati globali in validator.php // pertanto possono essere utilizzati direttamente all'interno di main.php foreach($item_idref_array as $elem_it) { if (array_search($elem_it, $idres_array) === false) { return 'mismatch'; } } foreach($def_org_array as $elem_def) { if (array_search($elem_it, $id_org_array) === false) { return 'mismatch'; } } } else { return 'badmanifest'; } } return 'regular'; } else { return 'found'; } } } else { return 'nomanifest'; } } function scorm_delete_files($directory) { if (is_dir($directory)) { $files=scorm_scandir($directory); //print_r($files); foreach($files as $file) { if (($file != '.') && ($file != '..')) { if (!is_dir($directory.'/'.$file)) { //chmod($directory.'/'.$file,0777); unlink($directory.'/'.$file); } else { scorm_delete_files($directory.'/'.$file); } } } rmdir($directory); } } function scorm_scandir($directory) { if (version_compare(phpversion(),'5.0.0','>=')) { return scandir($directory); } else { $files = null; if ($dh = opendir($directory)) { while (($file = readdir($dh)) !== false) { $files[] = $file; } closedir($dh); } return $files; } } function scorm_startElement($parser, $name, $attrs) { global $scoes,$i,$resources,$parent,$level,$organization,$manifest,$defaultorg; switch ($name) { case 'ITEM': $i++; $scoes[$i]['manifest'] = $manifest; $scoes[$i]['organization'] = $organization; $scoes[$i]['identifier'] = $attrs['IDENTIFIER']; if (empty($attrs['IDENTIFIERREF'])) $attrs['IDENTIFIERREF'] = ''; $scoes[$i]['identifierref'] = $attrs['IDENTIFIERREF']; if (empty($attrs['ISVISIBLE'])) $attrs['ISVISIBLE'] = ''; $scoes[$i]['isvisible'] = $attrs['ISVISIBLE']; if (empty($attrs['PARAMETERS'])) $attrs['PARAMETERS'] = ''; $scoes[$i]['parameters'] = $attrs['PARAMETERS']; $scoes[$i]['parent'] = $parent[$level]; $level++; $parent[$level] = $attrs['IDENTIFIER']; break; case 'RESOURCE': if (!isset($attrs['HREF'])) { $attrs['HREF'] = ''; } $resources[$attrs['IDENTIFIER']]['href']=$attrs['HREF']; if (!isset($attrs['ADLCP:SCORMTYPE'])) { $attrs['ADLCP:SCORMTYPE'] = ''; } $resources[$attrs['IDENTIFIER']]['scormtype']=$attrs['ADLCP:SCORMTYPE']; break; case 'ORGANIZATION': $i++; $scoes[$i]['manifest'] = $manifest; $scoes[$i]['organization'] = ''; $scoes[$i]['identifier'] = $attrs['IDENTIFIER']; $scoes[$i]['identifierref'] = ''; $scoes[$i]['isvisible'] = ''; $scoes[$i]['parent'] = $parent[$level]; $level++; $parent[$level] = $attrs['IDENTIFIER']; $organization = $attrs['IDENTIFIER']; break; case 'MANIFEST': $manifest = $attrs['IDENTIFIER']; break; case 'ORGANIZATIONS': if (!isset($attrs['DEFAULT'])) { $attrs['DEFAULT'] = ''; } $defaultorg = $attrs['DEFAULT']; break; } } function scorm_endElement($parser, $name) { global $scoes,$i,$level,$datacontent,$navigation; if ($name == 'ITEM') { $level--; } //if ($name == 'TITLE' && $level>0) { if ($name == 'TITLE') { $scoes[$i]['title'] = $datacontent; } if ($name == 'ADLCP:HIDERTSUI') { $scoes[$i][$datacontent] = 1; } if ($name == 'ADLCP:DATAFROMLMS') { $scoes[$i]['datafromlms'] = $datacontent; } if ($name == 'ADLCP:PREREQUISITES') { $scoes[$i]['prerequisites'] = $datacontent; } if ($name == 'ADLCP:MAXTIMEALLOWED') { $scoes[$i]['maxtimeallowed'] = $datacontent; } if ($name == 'ADLCP:TIMELIMITACTION') { $scoes[$i]['timelimitaction'] = $datacontent; } if ($name == 'ADLCP:MASTERYSCORE') { $scoes[$i]['masteryscore'] = $datacontent; } if ($name == 'ORGANIZATION') { $organization = ''; $level--; } if ($name == 'MANIFEST') { $manifest = ''; } } function scorm_characterData($parser, $data) { global $datacontent; $datacontent = utf8_decode($data); } function scorm_parse($basedir,$file,$scorm_id) { global $scoes,$i,$resources,$parent,$level,$defaultorg; $datacontent = ''; $scoes[][] = ''; $resources[] = ''; $organization = ''; $defaultorg = ''; $i = 0; $level = 0; $parent[$level] = '/'; $xml_parser = xml_parser_create('UTF-8'); // use case-folding so we are sure to find the tag in $map_array xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true); xml_set_element_handler($xml_parser, 'scorm_startElement', 'scorm_endElement'); xml_set_character_data_handler($xml_parser, 'scorm_characterData'); if (!($fp = fopen($basedir.$file, 'r'))) { die('could not open XML input'); } while ($data = fread($fp, 4096)) { if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf('XML error: %s at line %d', xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } } xml_parser_free($xml_parser); $launch = 0; $sco->scorm = $scorm_id; delete_records('scorm_scoes','scorm',$scorm_id); delete_records('scorm_scoes_track','scormid',$scorm_id); if (isset($scoes[1])) { for ($j=1; $j<=$i; $j++) { $sco->identifier = $scoes[$j]['identifier']; $sco->parent = $scoes[$j]['parent']; $sco->title = $scoes[$j]['title']; $sco->organization = $scoes[$j]['organization']; if (!isset($scoes[$j]['datafromlms'])) { $scoes[$j]['datafromlms'] = ''; } $sco->datafromlms = $scoes[$j]['datafromlms']; if (!isset($scoes[$j]['prerequisites'])) { $scoes[$j]['prerequisites'] = ''; } $sco->prerequisites = $scoes[$j]['prerequisites']; if (!isset($scoes[$j]['maxtimeallowed'])) { $scoes[$j]['maxtimeallowed'] = ''; } $sco->maxtimeallowed = $scoes[$j]['maxtimeallowed']; if (!isset($scoes[$j]['timelimitaction'])) { $scoes[$j]['timelimitaction'] = ''; } $sco->timelimitaction = $scoes[$j]['timelimitaction']; if (!isset($scoes[$j]['masteryscore'])) { $scoes[$j]['masteryscore'] = ''; } $sco->masteryscore = $scoes[$j]['masteryscore']; if (!isset($resources[($scoes[$j]['identifierref'])]['href'])) { $resources[($scoes[$j]['identifierref'])]['href'] = ''; } $sco->launch = $resources[($scoes[$j]['identifierref'])]['href']; if (!isset($scoes[$j]['parameters'])) { $scoes[$j]['paramenters'] = ''; } $sco->paramenters = $scoes[$j]['parameters']; if (!isset($resources[($scoes[$j]['identifierref'])]['type'])) { $resources[($scoes[$j]['identifierref'])]['type'] = ''; } $sco->type = $resources[($scoes[$j]['identifierref'])]['type']; if (!isset($scoes[$j]['previous'])) { $scoes[$j]['previous'] = 0; } $sco->previous = $scoes[$j]['previous']; if (!isset($scoes[$j]['continue'])) { $scoes[$j]['continue'] = 0; } $sco->next = $scoes[$j]['continue']; if (scorm_remove_spaces($scoes[$j]['isvisible']) != 'false') { $id = insert_record('scorm_scoes',$sco); } //if (($launch==0) && (isset($sco->launch)) && ($defaultorg==$sco->organization)) { if (($launch==0) && ($defaultorg==$sco->identifier)) { $launch = $id; } } } else { foreach ($resources as $label => $resource) { if (!empty($resource['href'])) { $sco->identifier = $label; $sco->title = $label; $sco->parent = '/'; $sco->launch = $resource['href']; $sco->type = $resource['type']; $id = insert_record('scorm_scoes',$sco); if ($launch == 0) { $launch = $id; } } } } return $launch; } function scorm_get_tracks($scoid,$userid) { /// Gets all tracks of specified sco and user global $CFG; if ($tracks = get_records_select("scorm_scoes_track","userid=$userid AND scoid=$scoid")) { $user_tracks->userid = $userid; $user_tracks->scoid = $scoid; foreach ($tracks as $track) { $element = str_replace('.','_',$track->element); switch ($element) { case "cmi_core_lesson_status": case "cmi_completition_status": if ($track->value == 'not attempted') { $track->value = 'notattempted'; } $user_tracks->status = $track->value; break; case "cmi_core_score_raw": case "cmi_score_raw": $user_tracks->score_raw = $track->value; break; default: $user_tracks->{$element} = $track->value; } } //print_r($user_tracks); return $user_tracks; } else { return false; } } function scorm_get_scoes_records($sco_user) { /// Gets all info required to display the table of scorm results /// for report.php global $CFG; return get_records_sql("SELECT su.*, u.firstname, u.lastname, u.picture FROM {$CFG->prefix}scorm_scoes_track su, {$CFG->prefix}user u WHERE su.scormid = '$sco_user->scormid' AND su.userid = u.id AND su.userid = '$sco_user->userid' ORDER BY scoid"); } function scorm_remove_spaces($sourcestr) { // Remove blank space from a string $newstr=''; for( $i=0; $i$len ) { return "".substr($stringa,0,$len-4).'...'.substr($stringa,strlen($stringa)-1,1).''; } else return $stringa; } function scorm_external_link($link) { // check if a link is external $result = false; $link = strtolower($link); if (substr($link,0,7) == 'http://') $result = true; else if (substr($link,0,8) == 'https://') $result = true; else if (substr($link,0,4) == 'www.') $result = true; return $result; } ?>