Putting SCORM into maintree CVS, to make it easier to test.
[moodle.git] / mod / scorm / lib.php
1 <?PHP  // $Id$
3 /// Library of functions and constants for module scorm
4 /// (replace scorm with the name of your module and delete this line)
7 $scorm_CONSTANT = 7;     /// for example
8 $SCORM_TOP_FRAME_SIZE = 120;
9 $SCORM_LEFT_FRAME_SIZE = 210;
11 function scorm_add_instance($scorm) {
12 /// Given an object containing all the necessary data, 
13 /// (defined by the form in mod.html) this function 
14 /// will create a new instance and return the id number 
15 /// of the new instance.
17     $scorm->timemodified = time();
19     # May have to add extra stuff in here #
20     
21     return insert_record("scorm", $scorm);
22 }
25 function scorm_update_instance($scorm) {
26 /// Given an object containing all the necessary data, 
27 /// (defined by the form in mod.html) this function 
28 /// will update an existing instance with new data.
30     $scorm->timemodified = time();
31     $scorm->id = $scorm->instance;
33     # May have to add extra stuff in here #
35     return update_record("scorm", $scorm);
36 }
39 function scorm_delete_instance($id) {
40 /// Given an ID of an instance of this module, 
41 /// this function will permanently delete the instance 
42 /// and any data that depends on it.  
43         
44     require('../config.php');
46     if (! $scorm = get_record("scorm", "id", "$id")) {
47         return false;
48     }
50     $result = true;
52     # Delete any dependent files #
53     scorm_delete_files($CFG->dataroot."/".$scorm->course."/moddata/scorm".$scorm->datadir);
55     # Delete any dependent records here #
56     if (! delete_records("scorm_sco_users", "scormid", "$scorm->id")) {
57         $result = false;
58     }
59     if (! delete_records("scorm_scoes", "scorm", "$scorm->id")) {
60         $result = false;
61     }
62     if (! delete_records("scorm", "id", "$scorm->id")) {
63         $result = false;
64     }
65     
67     return $result;
68 }
70 function scorm_user_outline($course, $user, $mod, $scorm) {
71 /// Return a small object with summary information about what a 
72 /// user has done with a given particular instance of this module
73 /// Used for user activity reports.
74 /// $return->time = the time they did it
75 /// $return->info = a short text description
77     return $return;
78 }
80 function scorm_user_complete($course, $user, $mod, $scorm) {
81 /// Print a detailed representation of what a  user has done with 
82 /// a given particular instance of this module, for user activity reports.
84     return true;
85 }
87 function scorm_print_recent_activity(&$logs, $isteacher=false) {
88 /// Given a list of logs, assumed to be those since the last login 
89 /// this function prints a short list of changes related to this module
90 /// If isteacher is true then perhaps additional information is printed.
91 /// This function is called from course/lib.php: print_recent_activity()
93     global $CFG, $COURSE_TEACHER_COLOR;
95     return $content;  // True if anything was printed, otherwise false
96 }
98 function scorm_cron () {
99 /// Function to be run periodically according to the moodle cron
100 /// This function searches for things that need to be done, such 
101 /// as sending out mail, toggling flags etc ... 
103     global $CFG;
105     return true;
108 function scorm_grades($scormid) {
109 /// Must return an array of grades for a given instance of this module, 
110 /// indexed by user.  It also returns a maximum allowed grade.
112         global $CFG;
113         
114     $return->grades = NULL;
115     if ($sco_users=get_records_select("scorm_sco_users", "scormid='$scormid' GROUP BY userid")) {
116         foreach ($sco_users as $sco_user) {
117                 $user_data=get_records_select("scorm_sco_users","scormid='$scormid' AND userid='$sco_user->userid'");
118                 $scores->completed=0;
119                 $scores->browsed=0;
120                 $scores->incomplete=0;
121                 $scores->failed=0;
122                 $scores->notattempted=0;
123                 $result="";
124                 $data = current($user_data);
125                 foreach ($user_data as $data) {
126                         if ($data->cmi_core_lesson_status=="passed")
127                                 $scores->completed++;
128                         else
129                                 $scores->{scorm_remove_spaces($data->cmi_core_lesson_status)}++;
130                         
131                 }
132                 if ($scores->completed)
133                         $result.="<img src=\"$CFG->wwwroot/mod/scorm/pix/completed.gif\" alt=\"".get_string("completed","scorm")."\" title=\"".get_string("completed","scorm")."\"> $scores->completed ";
134                 if ($scores->incomplete)
135                         $result.="<img src=\"$CFG->wwwroot/mod/scorm/pix/incomplete.gif\" alt=\"".get_string("incomplete","scorm")."\" title=\"".get_string("incomplete","scorm")."\"> $scores->incomplete ";
136                 if ($scores->failed)
137                         $result.="<img src=\"$CFG->wwwroot/mod/scorm/pix/failed.gif\" alt=\"".get_string("failed","scorm")."\" title=\"".get_string("failed","scorm")."\"> $scores->failed ";
138                 if ($scores->browsed)
139                         $result.="<img src=\"$CFG->wwwroot/mod/scorm/pix/browsed.gif\" alt=\"".get_string("browsed","scorm")."\" title=\"".get_string("browsed","scorm")."\"> $scores->browsed ";
140                         if ($scores->notattempted)
141                         $result.="<img src=\"$CFG->wwwroot/mod/scorm/pix/notattempted.gif\" alt=\"".get_string("notattempted","scorm")."\" title=\"".get_string("notattempted","scorm")."\"> $scores->notattempted ";
142                 
143                 $return->grades[$sco_user->userid]=$result;
144         }
145         
146     }
147     
148     $return->maxgrade = count_records_select("scorm_scoes","scorm='$scormid' AND launch<>''");
150     return $return;
154 //////////////////////////////////////////////////////////////////////////////////////
155 /// Any other scorm functions go here.  Each of them must have a name that 
156 /// starts with scorm_
159 function scorm_randstring($len = "8")
161         $rstring = NULL;
162         for($i=0; $i<$len; $i++) {
163                 $char = chr(rand(48,122));
164                 while (!ereg("[a-zA-Z0-9]", $char)){
165                         if($char == $lchar) continue;
166                         $char = chr(rand(48,90));
167                 }
168                 $rstring .= $char;
169                 $lchar = $char;
170         }
171         return $rstring;
174 function scorm_mkdirs($strPath)
176  if (is_dir($strPath))
177         return true;
178  $pStrPath = dirname($strPath);
179  if (!scorm_mkdirs($pStrPath)) 
180         return false;
181  return mkdir($strPath);
183  
184 function scorm_datadir($strPath, $existingdir="", $prefix = "SCORM")
186         if (($existingdir!="") && (is_dir($strPath.$existingdir)))
187                 return $strPath.$existingdir;
188                 
189         if (is_dir($strPath)) {
190                 do {
191                         $datadir="/".$prefix.scorm_randstring();
192                 } while (file_exists($strPath.$datadir));
193                 mkdir($strPath.$datadir);
194                 return $strPath.$datadir;
195         } else {
196                 return false;
197         }
198
200 function scorm_validate($manifest)
202     if (is_file ($manifest)) {
203         if (file_exists($manifest))
204         {
205                 return "regular";
206         }
207     } else {
208             return "nomanifest";
209     }
212 function scorm_delete_files($directory)
214     if (is_dir($directory))
215     {
216         $handle=opendir($directory);
217         while (($file = readdir($handle)) != '')
218         {
219             if ($file != "." && $file != "..")
220             {
221                 if (!is_dir($directory."/".$file))
222                     unlink($directory."/".$file);
223                 else
224                     scorm_delete_files($directory."/".$file);
225             }
226         }
227         rmdir($directory);
228     }
231 function scorm_startElement($parser, $name, $attrs) {
232     global $manifest,$i,$resources,$parent,$level;
233     if ($name == "ITEM") {
234                 $i++;
235                 $manifest[$i]["identifier"] = $attrs["IDENTIFIER"];
236                 $manifest[$i]["identifierref"] = $attrs["IDENTIFIERREF"];
237                 $manifest[$i]["isvisible"] = $attrs["ISVISIBLE"];
238                 $manifest[$i]["parent"] = $parent[$level];
239                 $level++;
240                 $parent[$level] = $attrs["IDENTIFIER"];
241     }
242     if ($name == "RESOURCE") {
243                 $resources[$attrs["IDENTIFIER"]]["href"]=$attrs["HREF"];
244                 $resources[$attrs["IDENTIFIER"]]["type"]=$attrs["ADLCP:SCORMTYPE"];
245     }
248 function scorm_endElement($parser, $name) {
249     global $manifest,$i,$level,$datacontent,$navigation;
250     if ($name == "ITEM") {
251         $level--;
252     }
253     if ($name == "TITLE" && $level>0)
254                 $manifest[$i]["title"] = $datacontent;
255         if ($name == "ADLCP:HIDERTSUI")
256                 $manifest[$i][$datacontent] = 1;
259 function scorm_characterData($parser, $data) {
260     global $datacontent;
261     $datacontent = $data;
264 function scorm_parse($basedir,$file,$scorm_id) {
265     global $manifest,$i,$resources,$parent,$level;
266     $datacontent = "";
267     $manifest[][] = "";
268     $resources[] = "";
269     $i = 0;
270     $level = 0;
271     $parent[$level] = "/";
273     $xml_parser = xml_parser_create();
274     // use case-folding so we are sure to find the tag in $map_array
275     xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true);
276     xml_set_element_handler($xml_parser, "scorm_startElement", "scorm_endElement");
277     xml_set_character_data_handler($xml_parser, "scorm_characterData");
278     if (!($fp = fopen($basedir.$file, "r"))) {
279        die("could not open XML input");
280     }
282     while ($data = fread($fp, 4096)) {
283         if (!xml_parse($xml_parser, $data, feof($fp))) {
284             die(sprintf("XML error: %s at line %d",
285                     xml_error_string(xml_get_error_code($xml_parser)),
286                     xml_get_current_line_number($xml_parser)));
287         }
288     }
289     xml_parser_free($xml_parser);
290     $launch = 0;
292     $sco->scorm = $scorm_id;
293     delete_records("scorm_scoes","scorm",$scorm_id);
294     delete_records("scorm_sco_users","scormid",$scorm_id);
295     for ($j=1; $j<=$i; $j++) {
296         $sco->identifier = $manifest[$j]["identifier"];
297         $sco->parent = $manifest[$j]["parent"];
298         $sco->title = $manifest[$j]["title"];
299         $sco->launch = $resources[$manifest[$j]["identifierref"]]["href"];
300                 $sco->type = $resources[$manifest[$j]["identifierref"]]["type"];
301                 $sco->previous = $manifest[$j]["previous"];
302                 $sco->next = $manifest[$j]["continue"];
303                 if (scorm_remove_spaces($manifest[$j]["isvisible"]) != "false")
304                         $id = insert_record("scorm_scoes",$sco);
305                 if ($launch==0 && $sco->launch)
306                         $launch = $id;  
307     }
308     return $launch;
311 function scorm_get_scoes_records($sco_user) {
312 /// Gets all info required to display the table of scorm results
313 /// for report.php
314     global $CFG;
316     return get_records_sql("SELECT su.*, u.firstname, u.lastname, u.picture 
317                             FROM {$CFG->prefix}scorm_sco_users su, 
318                                  {$CFG->prefix}user u
319                             WHERE su.scormid = '$sco_user->scormid'
320                               AND su.userid = u.id
321                               AND su.userid = $sco_user->userid
322                               ORDER BY scoid");
325 function scorm_remove_spaces($sourcestr) {
326 // Remove blank space from a string
327     $newstr="";
328         for( $i=0; $i<strlen($sourcestr); $i++) {
329                 if ($sourcestr[$i]!=' ')
330                         $newstr .=$sourcestr[$i];
331         }
332         return $newstr;
335 function scorm_string_round($stringa) {
336 // Crop a string to $len character and set an anchor title to the full string
337     $len=11;
338     if ( strlen($stringa)>$len ) {
339         return "<A name=\"\" title=\"$stringa\">".substr($stringa,0,$len-4)."...".substr($stringa,strlen($stringa)-1,1)."</A>";
340     } else
341         return $stringa;
344 function scorm_external_link($link) {
345 // check if a link is external
346     $result = false;
347     $link = strtolower($link);
348     if (substr($link,0,7) == "http://")
349         $result = true;
350     else if (substr($link,0,8) == "https://")
351         $result = true;
352     else if (substr($link,0,4) == "www.")
353         $result = true;
354     else if (substr($link,0,7) == "rstp://")
355         $result = true;
356     else if (substr($link,0,6) == "rtp://")
357         $result = true;
358     else if (substr($link,0,6) == "ftp://")
359         $result = true;
360     else if (substr($link,0,9) == "gopher://")
361         $result = true;
362     return $result;
363 }    
364 ?>