e4aa175a |
1 | <?php // $Id$ |
f69db63e |
2 | |
e4aa175a |
3 | define("VALUESCOES",0); |
4 | define("VALUEHIGHEST",1); |
5 | define("VALUEAVERAGE",2); |
6 | define("VALUESUM",3); |
7 | |
5c1ac70c |
8 | // |
9 | // Repository configurations |
10 | // |
11 | $repositoryconfigfile = $CFG->dirroot.'/mod/resource/type/ims/repository_config.php'; |
12 | $repositorybrowser = '/mod/resource/type/ims/finder.php'; |
f69db63e |
13 | |
f69db63e |
14 | |
5c1ac70c |
15 | /// Local Library of functions and constants for module scorm |
f69db63e |
16 | |
5c1ac70c |
17 | /** |
18 | * This function will permanently delete the given |
19 | * directory and all files and subdirectories. |
20 | * |
21 | * @param string $directory The directory to remove |
22 | * @return boolean |
23 | */ |
24 | function scorm_delete_files($directory) { |
25 | if (is_dir($directory)) { |
26 | $files=scorm_scandir($directory); |
27 | foreach($files as $file) { |
28 | if (($file != '.') && ($file != '..')) { |
29 | if (!is_dir($directory.'/'.$file)) { |
30 | unlink($directory.'/'.$file); |
31 | } else { |
32 | scorm_delete_files($directory.'/'.$file); |
33 | } |
f69db63e |
34 | } |
5c1ac70c |
35 | set_time_limit(5); |
f69db63e |
36 | } |
5c1ac70c |
37 | rmdir($directory); |
38 | return true; |
f69db63e |
39 | } |
5c1ac70c |
40 | return false; |
f69db63e |
41 | } |
42 | |
5c1ac70c |
43 | /** |
44 | * Given a diretory path returns the file list |
45 | * |
46 | * @param string $directory |
47 | * @return array |
48 | */ |
49 | function scorm_scandir($directory) { |
50 | if (version_compare(phpversion(),'5.0.0','>=')) { |
51 | return scandir($directory); |
f69db63e |
52 | } else { |
5c1ac70c |
53 | $files = array(); |
54 | if ($dh = opendir($directory)) { |
55 | while (($file = readdir($dh)) !== false) { |
56 | $files[] = $file; |
57 | } |
58 | closedir($dh); |
59 | } |
60 | return $files; |
f69db63e |
61 | } |
f69db63e |
62 | } |
63 | |
e4aa175a |
64 | /** |
65 | * Create a new temporary subdirectory with a random name in the given path |
66 | * |
67 | * @param string $strpath The scorm data directory |
68 | * @return string/boolean |
69 | */ |
70 | function scorm_datadir($strPath) |
71 | { |
72 | global $CFG; |
73 | |
74 | if (is_dir($strPath)) { |
75 | do { |
76 | // Create a random string of 8 chars |
77 | $randstring = NULL; |
78 | $lchar = ''; |
79 | $len = 8; |
80 | for ($i=0; $i<$len; $i++) { |
81 | $char = chr(rand(48,122)); |
82 | while (!ereg('[a-zA-Z0-9]', $char)){ |
83 | if ($char == $lchar) continue; |
84 | $char = chr(rand(48,90)); |
85 | } |
86 | $randstring .= $char; |
87 | $lchar = $char; |
88 | } |
89 | $datadir='/'.$randstring; |
90 | } while (file_exists($strPath.$datadir)); |
91 | mkdir($strPath.$datadir, $CFG->directorypermissions); |
92 | @chmod($strPath.$datadir, $CFG->directorypermissions); // Just in case mkdir didn't do it |
93 | return $strPath.$datadir; |
94 | } else { |
95 | return false; |
96 | } |
97 | } |
98 | |
99 | /** |
100 | * Given a package directory, this function will check if the package is valid |
101 | * |
102 | * @param string $packagedir The package directory |
103 | * @return mixed |
104 | */ |
105 | function scorm_validate($packagedir) { |
e4aa175a |
106 | $validation = new stdClass(); |
107 | if (is_file($packagedir.'/imsmanifest.xml')) { |
108 | $validation->result = 'found'; |
109 | $validation->pkgtype = 'SCORM'; |
110 | } else { |
111 | if ($handle = opendir($packagedir)) { |
112 | while (($file = readdir($handle)) !== false) { |
113 | $ext = substr($file,strrpos($file,'.')); |
114 | if (strtolower($ext) == '.cst') { |
115 | $validation->result = 'found'; |
116 | $validation->pkgtype = 'AICC'; |
117 | break; |
118 | } |
119 | } |
120 | closedir($handle); |
121 | } |
122 | if (!isset($validation->result)) { |
123 | $validation->result = 'nomanifest'; |
124 | $validation->pkgtype = 'SCORM'; |
125 | } |
126 | } |
127 | return $validation; |
128 | } |
129 | |
130 | function scorm_get_user_data($userid) { |
131 | /// Gets user info required to display the table of scorm results |
132 | /// for report.php |
133 | |
134 | return get_record('user','id',$userid,'','','','','firstname, lastname, picture'); |
135 | } |
136 | |
137 | function scorm_string_wrap($stringa, $len=15) { |
138 | // Crop the given string into max $len characters lines |
139 | $textlib = textlib_get_instance(); |
140 | if ($textlib->strlen($stringa, current_charset()) > $len) { |
141 | $words = explode(' ', $stringa); |
142 | $newstring = ''; |
143 | $substring = ''; |
144 | foreach ($words as $word) { |
145 | if (($textlib->strlen($substring, current_charset())+$textlib->strlen($word, current_charset())+1) < $len) { |
146 | $substring .= ' '.$word; |
147 | } else { |
148 | $newstring .= ' '.$substring.'<br />'; |
149 | $substring = $word; |
150 | } |
151 | } |
152 | if (!empty($substring)) { |
153 | $newstring .= ' '.$substring; |
154 | } |
155 | return $newstring; |
156 | } else { |
157 | return $stringa; |
158 | } |
159 | } |
160 | |
161 | function scorm_eval_prerequisites($prerequisites,$usertracks) { |
e4aa175a |
162 | $element = ''; |
163 | $stack = array(); |
164 | $statuses = array( |
165 | 'passed' => 'passed', |
166 | 'completed' => 'completed', |
167 | 'failed' => 'failed', |
168 | 'incomplete' => 'incomplete', |
169 | 'browsed' => 'browsed', |
170 | 'not attempted' => 'notattempted', |
171 | 'p' => 'passed', |
172 | 'c' => 'completed', |
173 | 'f' => 'failed', |
174 | 'i' => 'incomplete', |
175 | 'b' => 'browsed', |
176 | 'n' => 'notattempted' |
177 | ); |
178 | $i=0; |
179 | while ($i<strlen($prerequisites)) { |
180 | $symbol = $prerequisites[$i]; |
181 | switch ($symbol) { |
182 | case '&': |
183 | case '|': |
184 | $symbol .= $symbol; |
185 | case '~': |
186 | case '(': |
187 | case ')': |
188 | case '*': |
e4aa175a |
189 | $element = trim($element); |
190 | |
191 | if (!empty($element)) { |
192 | $element = trim($element); |
193 | if (isset($usertracks[$element])) { |
194 | $element = '((\''.$usertracks[$element]->status.'\' == \'completed\') || '. |
195 | '(\''.$usertracks[$element]->status.'\' == \'passed\'))'; |
196 | } else if (($operator = strpos($element,'=')) !== false) { |
197 | $item = trim(substr($element,0,$operator)); |
198 | if (!isset($usertracks[$item])) { |
199 | return false; |
200 | } |
201 | |
202 | $value = trim(trim(substr($element,$operator+1)),'"'); |
203 | if (isset($statuses[$value])) { |
204 | $status = $statuses[$value]; |
205 | } else { |
206 | return false; |
207 | } |
208 | |
209 | $element = '(\''.$usertracks[$item]->status.'\' == \''.$status.'\')'; |
210 | } else if (($operator = strpos($element,'<>')) !== false) { |
211 | $item = trim(substr($element,0,$operator)); |
212 | if (!isset($usertracks[$item])) { |
213 | return false; |
214 | } |
215 | |
216 | $value = trim(trim(substr($element,$operator+2)),'"'); |
217 | if (isset($statuses[$value])) { |
218 | $status = $statuses[$value]; |
219 | } else { |
220 | return false; |
221 | } |
222 | |
223 | $element = '(\''.$usertracks[$item]->status.'\' != \''.$status.'\')'; |
224 | } else if (is_numeric($element)) { |
225 | if ($symbol == '*') { |
226 | $symbol = ''; |
227 | $open = strpos($prerequisites,'{',$i); |
228 | $opened = 1; |
229 | $closed = 0; |
230 | for ($close=$open+1; (($opened > $closed) && ($close<strlen($prerequisites))); $close++) { |
231 | if ($prerequisites[$close] == '}') { |
232 | $closed++; |
233 | } else if ($prerequisites[$close] == '{') { |
234 | $opened++; |
235 | } |
236 | } |
237 | $i = $close; |
238 | |
239 | $setelements = explode(',', substr($prerequisites, $open+1, $close-($open+1)-1)); |
240 | $settrue = 0; |
241 | foreach ($setelements as $setelement) { |
242 | if (scorm_eval_prerequisites($setelement,$usertracks)) { |
243 | $settrue++; |
244 | } |
245 | } |
246 | |
247 | if ($settrue >= $element) { |
248 | $element = 'true'; |
249 | } else { |
250 | $element = 'false'; |
251 | } |
252 | } |
253 | } else { |
254 | return false; |
255 | } |
256 | |
257 | array_push($stack,$element); |
258 | $element = ''; |
259 | } |
260 | if ($symbol == '~') { |
261 | $symbol = '!'; |
262 | } |
263 | if (!empty($symbol)) { |
264 | array_push($stack,$symbol); |
265 | } |
266 | break; |
267 | default: |
268 | $element .= $symbol; |
269 | break; |
270 | } |
271 | $i++; |
272 | } |
273 | if (!empty($element)) { |
274 | $element = trim($element); |
275 | if (isset($usertracks[$element])) { |
276 | $element = '((\''.$usertracks[$element]->status.'\' == \'completed\') || '. |
277 | '(\''.$usertracks[$element]->status.'\' == \'passed\'))'; |
278 | } else if (($operator = strpos($element,'=')) !== false) { |
279 | $item = trim(substr($element,0,$operator)); |
280 | if (!isset($usertracks[$item])) { |
281 | return false; |
282 | } |
283 | |
284 | $value = trim(trim(substr($element,$operator+1)),'"'); |
285 | if (isset($statuses[$value])) { |
286 | $status = $statuses[$value]; |
287 | } else { |
288 | return false; |
289 | } |
290 | |
291 | $element = '(\''.$usertracks[$item]->status.'\' == \''.$status.'\')'; |
292 | } else if (($operator = strpos($element,'<>')) !== false) { |
293 | $item = trim(substr($element,0,$operator)); |
294 | if (!isset($usertracks[$item])) { |
295 | return false; |
296 | } |
297 | |
298 | $value = trim(trim(substr($element,$operator+1)),'"'); |
299 | if (isset($statuses[$value])) { |
300 | $status = $statuses[$value]; |
301 | } else { |
302 | return false; |
303 | } |
304 | |
305 | $element = '(\''.$usertracks[$item]->status.'\' != \''.trim($status).'\')'; |
306 | } else { |
307 | return false; |
308 | } |
309 | |
310 | array_push($stack,$element); |
311 | } |
312 | return eval('return '.implode($stack).';'); |
313 | } |
314 | |
e4aa175a |
315 | function scorm_insert_track($userid,$scormid,$scoid,$attempt,$element,$value) { |
e4aa175a |
316 | $id = null; |
317 | if ($track = get_record_select('scorm_scoes_track',"userid='$userid' AND scormid='$scormid' AND scoid='$scoid' AND attempt='$attempt' AND element='$element'")) { |
318 | $track->value = $value; |
319 | $track->timemodified = time(); |
e4aa175a |
320 | $id = update_record('scorm_scoes_track',$track); |
321 | } else { |
322 | $track->userid = $userid; |
323 | $track->scormid = $scormid; |
324 | $track->scoid = $scoid; |
325 | $track->attempt = $attempt; |
326 | $track->element = $element; |
327 | $track->value = addslashes($value); |
328 | $track->timemodified = time(); |
e4aa175a |
329 | $id = insert_record('scorm_scoes_track',$track); |
330 | } |
331 | return $id; |
332 | } |
333 | |
e4aa175a |
334 | function scorm_add_time($a, $b) { |
335 | $aes = explode(':',$a); |
336 | $bes = explode(':',$b); |
337 | $aseconds = explode('.',$aes[2]); |
338 | $bseconds = explode('.',$bes[2]); |
339 | $change = 0; |
340 | |
341 | $acents = 0; //Cents |
342 | if (count($aseconds) > 1) { |
343 | $acents = $aseconds[1]; |
344 | } |
345 | $bcents = 0; |
346 | if (count($bseconds) > 1) { |
347 | $bcents = $bseconds[1]; |
348 | } |
349 | $cents = $acents + $bcents; |
350 | $change = floor($cents / 100); |
351 | $cents = $cents - ($change * 100); |
352 | if (floor($cents) < 10) { |
353 | $cents = '0'. $cents; |
f69db63e |
354 | } |
e4aa175a |
355 | |
f69db63e |
356 | $secs = $aseconds[0] + $bseconds[0] + $change; //Seconds |
357 | $change = floor($secs / 60); |
358 | $secs = $secs - ($change * 60); |
359 | if (floor($secs) < 10) { |
360 | $secs = '0'. $secs; |
361 | } |
e4aa175a |
362 | |
f69db63e |
363 | $mins = $aes[1] + $bes[1] + $change; //Minutes |
364 | $change = floor($mins / 60); |
365 | $mins = $mins - ($change * 60); |
366 | if ($mins < 10) { |
367 | $mins = '0' . $mins; |
368 | } |
e4aa175a |
369 | |
f69db63e |
370 | $hours = $aes[0] + $bes[0] + $change; //Hours |
371 | if ($hours < 10) { |
372 | $hours = '0' . $hours; |
373 | } |
e4aa175a |
374 | |
f69db63e |
375 | if ($cents != '0') { |
376 | return $hours . ":" . $mins . ":" . $secs . '.' . $cents; |
377 | } else { |
378 | return $hours . ":" . $mins . ":" . $secs; |
e4aa175a |
379 | } |
e4aa175a |
380 | } |
381 | |
f69db63e |
382 | function scorm_external_link($link) { |
383 | // check if a link is external |
384 | $result = false; |
385 | $link = strtolower($link); |
386 | if (substr($link,0,7) == 'http://') { |
387 | $result = true; |
388 | } else if (substr($link,0,8) == 'https://') { |
389 | $result = true; |
390 | } else if (substr($link,0,4) == 'www.') { |
391 | $result = true; |
392 | } |
393 | return $result; |
394 | } |
e4aa175a |
395 | |
f69db63e |
396 | function scorm_grade_user($scoes, $userid, $grademethod=VALUESCOES) { |
e4aa175a |
397 | $scores = NULL; |
398 | $scores->scoes = 0; |
399 | $scores->values = 0; |
e4aa175a |
400 | $scores->max = 0; |
401 | $scores->sum = 0; |
402 | |
403 | if (!$scoes) { |
e4aa175a |
404 | return ''; |
405 | } |
406 | |
407 | $current = current($scoes); |
408 | $attempt = scorm_get_last_attempt($current->scorm, $userid); |
e4aa175a |
409 | foreach ($scoes as $sco) { |
410 | if ($userdata=scorm_get_tracks($sco->id, $userid,$attempt)) { |
f69db63e |
411 | if (($userdata->status == 'completed') || ($userdata->status == 'passed')) { |
e4aa175a |
412 | $scores->scoes++; |
f69db63e |
413 | } |
e4aa175a |
414 | if (!empty($userdata->score_raw)) { |
415 | $scores->values++; |
416 | $scores->sum += $userdata->score_raw; |
417 | $scores->max = ($userdata->score_raw > $scores->max)?$userdata->score_raw:$scores->max; |
e4aa175a |
418 | } |
e4aa175a |
419 | } |
420 | } |
e4aa175a |
421 | switch ($grademethod) { |
422 | case VALUEHIGHEST: |
e4aa175a |
423 | return $scores->max; |
424 | break; |
425 | case VALUEAVERAGE: |
e4aa175a |
426 | if ($scores->values > 0) { |
427 | return $scores->sum/$scores->values; |
428 | } else { |
429 | return 0; |
430 | } |
431 | break; |
432 | case VALUESUM: |
e4aa175a |
433 | return $scores->sum; |
434 | break; |
435 | case VALUESCOES: |
f69db63e |
436 | return $scores->scoes; |
e4aa175a |
437 | break; |
438 | } |
439 | } |
440 | |
441 | function scorm_count_launchable($scormid,$organization) { |
442 | return count_records_select('scorm_scoes',"scorm=$scormid AND organization='$organization' AND launch<>''"); |
443 | } |
444 | |
445 | function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='normal',$attempt='',$play=false) { |
446 | global $CFG; |
f69db63e |
447 | |
448 | // Added by Pham Minh Duc |
e4aa175a |
449 | $suspendscoid = scorm_get_suspendscoid($scorm->id,$user->id); |
f69db63e |
450 | // End add |
e4aa175a |
451 | |
452 | $strexpand = get_string('expcoll','scorm'); |
453 | $modestr = ''; |
454 | if ($mode == 'browse') { |
455 | $modestr = '&mode='.$mode; |
456 | } |
457 | $scormpixdir = $CFG->modpixpath.'/scorm/pix'; |
458 | |
459 | $result = new stdClass(); |
460 | $result->toc = "<ul id='0' class='$liststyle'>\n"; |
461 | $tocmenus = array(); |
462 | $result->prerequisites = true; |
463 | $incomplete = false; |
464 | |
465 | // |
466 | // Get the current organization infos |
467 | // |
468 | $organizationsql = ''; |
469 | if (!empty($currentorg)) { |
470 | if (($organizationtitle = get_field('scorm_scoes','title','scorm',$scorm->id,'identifier',$currentorg)) != '') { |
471 | $result->toc .= "\t<li>$organizationtitle</li>\n"; |
472 | $tocmenus[] = $organizationtitle; |
473 | } |
474 | $organizationsql = "AND organization='$currentorg'"; |
475 | } |
476 | // |
477 | // If not specified retrieve the last attempt number |
478 | // |
479 | if (empty($attempt)) { |
480 | $attempt = scorm_get_last_attempt($scorm->id, $user->id); |
481 | } |
482 | $result->attemptleft = $scorm->maxattempt - $attempt; |
e4aa175a |
483 | if ($scoes = get_records_select('scorm_scoes',"scorm='$scorm->id' $organizationsql order by id ASC")){ |
5c1ac70c |
484 | // |
485 | // Retrieve user tracking data for each learning object |
486 | // |
e4aa175a |
487 | $usertracks = array(); |
488 | foreach ($scoes as $sco) { |
e4aa175a |
489 | if (!empty($sco->launch)) { |
490 | if ($usertrack=scorm_get_tracks($sco->id,$user->id,$attempt)) { |
491 | if ($usertrack->status == '') { |
492 | $usertrack->status = 'notattempted'; |
493 | } |
e4aa175a |
494 | $usertracks[$sco->identifier] = $usertrack; |
495 | } |
496 | } |
497 | } |
498 | |
499 | $level=0; |
500 | $sublist=1; |
501 | $previd = 0; |
502 | $nextid = 0; |
503 | $findnext = false; |
504 | $parents[$level]='/'; |
505 | |
506 | foreach ($scoes as $sco) { |
507 | if ($parents[$level]!=$sco->parent) { |
508 | if ($newlevel = array_search($sco->parent,$parents)) { |
509 | for ($i=0; $i<($level-$newlevel); $i++) { |
510 | $result->toc .= "\t\t</ul></li>\n"; |
511 | } |
512 | $level = $newlevel; |
513 | } else { |
514 | $i = $level; |
515 | $closelist = ''; |
516 | while (($i > 0) && ($parents[$level] != $sco->parent)) { |
517 | $closelist .= "\t\t</ul></li>\n"; |
518 | $i--; |
519 | } |
520 | if (($i == 0) && ($sco->parent != $currentorg)) { |
521 | $style = ''; |
522 | if (isset($_COOKIE['hide:SCORMitem'.$sco->id])) { |
523 | $style = ' style="display: none;"'; |
524 | } |
525 | $result->toc .= "\t\t<li><ul id='$sublist' class='$liststyle'$style>\n"; |
526 | $level++; |
527 | } else { |
528 | $result->toc .= $closelist; |
529 | $level = $i; |
530 | } |
531 | $parents[$level]=$sco->parent; |
532 | } |
533 | } |
534 | $result->toc .= "\t\t<li>"; |
535 | $nextsco = next($scoes); |
536 | if (($nextsco !== false) && ($sco->parent != $nextsco->parent) && (($level==0) || (($level>0) && ($nextsco->parent == $sco->identifier)))) { |
537 | $sublist++; |
538 | $icon = 'minus'; |
539 | if (isset($_COOKIE['hide:SCORMitem'.$nextsco->id])) { |
540 | $icon = 'plus'; |
541 | } |
542 | $result->toc .= '<a href="javascript:expandCollide(img'.$sublist.','.$sublist.','.$nextsco->id.');"><img id="img'.$sublist.'" src="'.$scormpixdir.'/'.$icon.'.gif" alt="'.$strexpand.'" title="'.$strexpand.'"/></a>'; |
543 | } else { |
544 | $result->toc .= '<img src="'.$scormpixdir.'/spacer.gif" />'; |
545 | } |
546 | if (empty($sco->title)) { |
547 | $sco->title = $sco->identifier; |
548 | } |
549 | if (!empty($sco->launch)) { |
550 | $startbold = ''; |
551 | $endbold = ''; |
552 | $score = ''; |
553 | if (empty($scoid) && ($mode != 'normal')) { |
554 | $scoid = $sco->id; |
555 | } |
5c1ac70c |
556 | // Modified by Pham Minh Duc |
e4aa175a |
557 | if ($suspendscoid == $sco->id){ |
558 | $result->toc .= '<img src="'.$scormpixdir.'/suspend.gif" alt="Dang tam dung o day" title="Dang dung o day" />'; |
559 | } else { |
e4aa175a |
560 | if (isset($usertracks[$sco->identifier])) { |
561 | $usertrack = $usertracks[$sco->identifier]; |
562 | $strstatus = get_string($usertrack->status,'scorm'); |
563 | $result->toc .= '<img src="'.$scormpixdir.'/'.$usertrack->status.'.gif" alt="'.$strstatus.'" title="'.$strstatus.'" />'; |
564 | |
565 | if (($usertrack->status == 'notattempted') || ($usertrack->status == 'incomplete') || ($usertrack->status == 'browsed')) { |
e4aa175a |
566 | $incomplete = true; |
567 | if ($play && empty($scoid)) { |
568 | $scoid = $sco->id; |
569 | } |
570 | } |
571 | if ($usertrack->score_raw != '') { |
572 | $score = '('.get_string('score','scorm').': '.$usertrack->score_raw.')'; |
573 | } |
574 | } else { |
575 | if ($play && empty($scoid)) { |
576 | $scoid = $sco->id; |
577 | } |
578 | if ($sco->scormtype == 'sco') { |
579 | $result->toc .= '<img src="'.$scormpixdir.'/notattempted.gif" alt="'.get_string('notattempted','scorm').'" title="'.get_string('notattempted','scorm').'" />'; |
580 | $incomplete = true; |
581 | } else { |
582 | $result->toc .= '<img src="'.$scormpixdir.'/asset.gif" alt="'.get_string('asset','scorm').'" title="'.get_string('asset','scorm').'" />'; |
583 | } |
584 | } |
585 | } |
5c1ac70c |
586 | // End Modify |
e4aa175a |
587 | if ($sco->id == $scoid) { |
588 | $startbold = '<b>'; |
589 | $endbold = '</b>'; |
590 | $findnext = true; |
591 | $shownext = $sco->next; |
592 | $showprev = $sco->previous; |
593 | } |
594 | |
595 | if (($nextid == 0) && (scorm_count_launchable($scorm->id,$currentorg) > 1) && ($nextsco!==false) && (!$findnext)) { |
596 | if (!empty($sco->launch)) { |
597 | $previd = $sco->id; |
598 | } |
599 | } |
600 | if (empty($sco->prerequisites) || scorm_eval_prerequisites($sco->prerequisites,$usertracks)) { |
601 | if ($sco->id == $scoid) { |
602 | $result->prerequisites = true; |
603 | } |
f69db63e |
604 | // Modified by Pham Minh Duc |
605 | if (scorm_isChoice($scorm->id,$sco->id) == 1) { |
606 | $url = $CFG->wwwroot.'/mod/scorm/player.php?a='.$scorm->id.'&currentorg='.$currentorg.$modestr.'&scoid='.$sco->id; |
607 | $result->toc .= ' '.$startbold.'<a href="'.$url.'">'.format_string($sco->title).'</a>'.$score.$endbold."</li>\n"; |
608 | $tocmenus[$sco->id] = scorm_repeater('−',$level) . '>' . format_string($sco->title); |
609 | } else { |
610 | $result->toc .= ' '.$startbold.format_string($sco->title).$score.$endbold."</li>\n"; |
611 | $tocmenus[$sco->id] = scorm_repeater('−',$level) . '>' . format_string($sco->title); |
e4aa175a |
612 | } |
f69db63e |
613 | // End modify |
e4aa175a |
614 | } else { |
615 | if ($sco->id == $scoid) { |
616 | $result->prerequisites = false; |
617 | } |
618 | $result->toc .= ' '.$sco->title."</li>\n"; |
619 | } |
620 | } else { |
621 | $result->toc .= ' '.$sco->title."</li>\n"; |
622 | } |
623 | if (($nextsco !== false) && ($nextid == 0) && ($findnext)) { |
624 | if (!empty($nextsco->launch)) { |
625 | $nextid = $nextsco->id; |
626 | } |
627 | } |
628 | } |
629 | for ($i=0;$i<$level;$i++) { |
630 | $result->toc .= "\t\t</ul></li>\n"; |
631 | } |
632 | |
633 | if ($play) { |
634 | $sco = get_record('scorm_scoes','id',$scoid); |
635 | $sco->previd = $previd; |
636 | $sco->nextid = $nextid; |
637 | $result->sco = $sco; |
638 | $result->incomplete = $incomplete; |
639 | } else { |
640 | $result->incomplete = $incomplete; |
641 | } |
642 | } |
643 | $result->toc .= "\t</ul>\n"; |
644 | if ($scorm->hidetoc == 0) { |
645 | $result->toc .= ' |
646 | <script language="javascript" type="text/javascript"> |
647 | <!-- |
648 | function expandCollide(which,list,item) { |
649 | var nn=document.ids?true:false |
650 | var w3c=document.getElementById?true:false |
651 | var beg=nn?"document.ids.":w3c?"document.getElementById(":"document.all."; |
652 | var mid=w3c?").style":".style"; |
653 | |
654 | if (eval(beg+list+mid+".display") != "none") { |
655 | which.src = "'.$scormpixdir.'/plus.gif"; |
656 | eval(beg+list+mid+".display=\'none\';"); |
657 | new cookie("hide:SCORMitem" + item, 1, 356, "/").set(); |
658 | } else { |
659 | which.src = "'.$scormpixdir.'/minus.gif"; |
660 | eval(beg+list+mid+".display=\'block\';"); |
661 | new cookie("hide:SCORMitem" + item, 1, -1, "/").set(); |
662 | } |
663 | } |
664 | --> |
665 | </script>'."\n"; |
666 | } |
667 | |
668 | $url = $CFG->wwwroot.'/mod/scorm/player.php?a='.$scorm->id.'&currentorg='.$currentorg.$modestr.'&scoid='; |
669 | $result->tocmenu = popup_form($url,$tocmenus, "tocmenu", $sco->id, '', '', '', true); |
670 | |
671 | return $result; |
672 | } |
673 | |
674 | function scorm_get_last_attempt($scormid, $userid) { |
e4aa175a |
675 | /// Find the last attempt number for the given user id and scorm id |
676 | if ($lastattempt = get_record('scorm_scoes_track', 'userid', $userid, 'scormid', $scormid, '', '', 'max(attempt) as a')) { |
677 | if (empty($lastattempt->a)) { |
678 | return '1'; |
679 | } else { |
680 | return $lastattempt->a; |
681 | } |
682 | } |
683 | } |
684 | |
e4aa175a |
685 | function scorm_get_tracks($scoid,$userid,$attempt='') { |
e4aa175a |
686 | /// Gets all tracks of specified sco and user |
687 | global $CFG; |
688 | |
689 | if (empty($attempt)) { |
690 | if ($scormid = get_field('scorm_scoes','scorm','id',$scoid)) { |
691 | $attempt = scorm_get_last_attempt($scormid,$userid); |
692 | } else { |
693 | $attempt = 1; |
694 | } |
695 | } |
696 | $attemptsql = ' AND attempt=' . $attempt; |
697 | if ($tracks = get_records_select('scorm_scoes_track',"userid=$userid AND scoid=$scoid".$attemptsql,'element ASC')) { |
698 | $usertrack->userid = $userid; |
699 | $usertrack->scoid = $scoid; |
700 | $usertrack->score_raw = ''; |
e4aa175a |
701 | $usertrack->status = ''; |
e4aa175a |
702 | $usertrack->total_time = '00:00:00'; |
703 | $usertrack->session_time = '00:00:00'; |
704 | $usertrack->timemodified = 0; |
f69db63e |
705 | // Added by Pham Minh Duc |
706 | $usertrack->score_scaled = ''; |
707 | $usertrack->success_status = ''; |
708 | $usertrack->attempt_status = ''; |
709 | $usertrack->satisfied_status = ''; |
710 | // End Add |
e4aa175a |
711 | foreach ($tracks as $track) { |
712 | $element = $track->element; |
713 | $usertrack->{$element} = $track->value; |
714 | switch ($element) { |
f69db63e |
715 | // Added by Pham Minh Duc |
e4aa175a |
716 | case 'cmi.attempt_status': |
717 | $usertrack->status = $track->value; |
718 | $usertrack->attempt_status = $track->value; |
719 | break; |
e4aa175a |
720 | case 'cmi.success_status': |
721 | $usertrack->success_status = $track->value; |
722 | if ($track->value=='passed'){ |
723 | $usertrack->satisfied_status = 'satisfied'; |
724 | } |
725 | if ($track->value=='failed'){ |
726 | $usertrack->satisfied_status = 'notSatisfied'; |
727 | } |
728 | break; |
f69db63e |
729 | case 'cmi.score.scaled': |
730 | $usertrack->score_scaled = $track->value; |
731 | break; |
732 | // End Add |
733 | case 'cmi.core.lesson_status': |
734 | case 'cmi.completion_status': |
735 | if ($track->value == 'not attempted') { |
736 | $track->value = 'notattempted'; |
737 | } |
738 | $usertrack->status = $track->value; |
739 | break; |
e4aa175a |
740 | case 'cmi.core.score.raw': |
741 | case 'cmi.score.raw': |
742 | $usertrack->score_raw = $track->value; |
743 | break; |
e4aa175a |
744 | case 'cmi.core.session_time': |
745 | case 'cmi.session_time': |
746 | $usertrack->session_time = $track->value; |
747 | break; |
748 | case 'cmi.core.total_time': |
749 | case 'cmi.total_time': |
750 | $usertrack->total_time = $track->value; |
751 | break; |
752 | } |
753 | if (isset($track->timemodified) && ($track->timemodified > $usertrack->timemodified)) { |
754 | $usertrack->timemodified = $track->timemodified; |
755 | } |
756 | } |
757 | return $usertrack; |
758 | } else { |
759 | return false; |
760 | } |
761 | } |
762 | |
e4aa175a |
763 | /// Library of functions and constants for parsing packages |
764 | |
765 | function scorm_parse($scorm) { |
5c1ac70c |
766 | global $CFG,$repositoryconfigfile; |
e4aa175a |
767 | |
e4aa175a |
768 | // Parse scorm manifest |
769 | if ($scorm->pkgtype == 'AICC') { |
770 | $scorm->launch = scorm_parse_aicc($scorm->dir.'/'.$scorm->id,$scorm->id); |
771 | } else { |
5c1ac70c |
772 | $reference = $scorm->reference; |
773 | if ($scorm->reference[0] == '#') { |
774 | require_once($repositoryconfigfile); |
775 | $reference = $CFG->repository.substr($scorm->reference,1).'/imsmanifest.xml'; |
776 | } else if (substr($reference,0,7) != 'http://') { |
777 | $reference = $CFG->dataroot.'/'.$scorm->course.'/'.$scorm->reference; |
778 | } |
779 | |
780 | if (basename($reference) != 'imsmanifest.xml') { |
e4aa175a |
781 | $scorm->launch = scorm_parse_scorm($scorm->dir.'/'.$scorm->id,$scorm->id); |
782 | } else { |
5c1ac70c |
783 | $scorm->launch = scorm_parse_scorm(dirname($reference),$scorm->id); |
e4aa175a |
784 | } |
785 | } |
e4aa175a |
786 | return $scorm->launch; |
787 | } |
788 | |
789 | /** |
790 | * Take the header row of an AICC definition file |
791 | * and returns sequence of columns and a pointer to |
792 | * the sco identifier column. |
793 | * |
794 | * @param string $row AICC header row |
795 | * @param string $mastername AICC sco identifier column |
796 | * @return mixed |
797 | */ |
798 | function scorm_get_aicc_columns($row,$mastername='system_id') { |
799 | $tok = strtok(strtolower($row),"\",\n\r"); |
800 | $result->columns = array(); |
801 | $i=0; |
802 | while ($tok) { |
803 | if ($tok !='') { |
804 | $result->columns[] = $tok; |
805 | if ($tok == $mastername) { |
806 | $result->mastercol = $i; |
807 | } |
808 | $i++; |
809 | } |
810 | $tok = strtok("\",\n\r"); |
811 | } |
812 | return $result; |
813 | } |
814 | |
815 | /** |
816 | * Given a colums array return a string containing the regular |
817 | * expression to match the columns in a text row. |
818 | * |
819 | * @param array $column The header columns |
820 | * @param string $remodule The regular expression module for a single column |
821 | * @return string |
822 | */ |
823 | function scorm_forge_cols_regexp($columns,$remodule='(".*")?,') { |
824 | $regexp = '/^'; |
825 | foreach ($columns as $column) { |
826 | $regexp .= $remodule; |
827 | } |
828 | $regexp = substr($regexp,0,-1) . '/'; |
829 | return $regexp; |
830 | } |
831 | |
5c1ac70c |
832 | function scorm_parse_aicc($pkgdir,$scormid) { |
e4aa175a |
833 | $version = 'AICC'; |
834 | $ids = array(); |
835 | $courses = array(); |
f69db63e |
836 | $extaiccfiles = array('crs','des','au','cst','ort','pre','cmp'); |
e4aa175a |
837 | if ($handle = opendir($pkgdir)) { |
838 | while (($file = readdir($handle)) !== false) { |
f69db63e |
839 | if ($file[0] != '.') { |
840 | $ext = substr($file,strrpos($file,'.')); |
841 | $extension = strtolower(substr($ext,1)); |
842 | if (in_array($extension,$extaiccfiles)) { |
843 | $id = strtolower(basename($file,$ext)); |
844 | $ids[$id]->$extension = $file; |
845 | } |
846 | } |
e4aa175a |
847 | } |
848 | closedir($handle); |
849 | } |
850 | foreach ($ids as $courseid => $id) { |
851 | if (isset($id->crs)) { |
852 | if (is_file($pkgdir.'/'.$id->crs)) { |
853 | $rows = file($pkgdir.'/'.$id->crs); |
854 | foreach ($rows as $row) { |
855 | if (preg_match("/^(.+)=(.+)$/",$row,$matches)) { |
856 | switch (strtolower(trim($matches[1]))) { |
857 | case 'course_id': |
858 | $courses[$courseid]->id = trim($matches[2]); |
859 | break; |
860 | case 'course_title': |
861 | $courses[$courseid]->title = trim($matches[2]); |
862 | break; |
863 | case 'version': |
864 | $courses[$courseid]->version = 'AICC_'.trim($matches[2]); |
865 | break; |
866 | } |
867 | } |
868 | } |
869 | } |
870 | } |
871 | if (isset($id->des)) { |
872 | $rows = file($pkgdir.'/'.$id->des); |
873 | $columns = scorm_get_aicc_columns($rows[0]); |
874 | $regexp = scorm_forge_cols_regexp($columns->columns); |
875 | for ($i=1;$i<count($rows);$i++) { |
876 | if (preg_match($regexp,$rows[$i],$matches)) { |
877 | for ($j=0;$j<count($columns->columns);$j++) { |
878 | $column = $columns->columns[$j]; |
879 | $courses[$courseid]->elements[substr(trim($matches[$columns->mastercol+1]),1,-1)]->$column = substr(trim($matches[$j+1]),1,-1); |
880 | } |
881 | } |
882 | } |
883 | } |
884 | if (isset($id->au)) { |
885 | $rows = file($pkgdir.'/'.$id->au); |
886 | $columns = scorm_get_aicc_columns($rows[0]); |
887 | $regexp = scorm_forge_cols_regexp($columns->columns); |
888 | for ($i=1;$i<count($rows);$i++) { |
889 | if (preg_match($regexp,$rows[$i],$matches)) { |
890 | for ($j=0;$j<count($columns->columns);$j++) { |
891 | $column = $columns->columns[$j]; |
892 | $courses[$courseid]->elements[substr(trim($matches[$columns->mastercol+1]),1,-1)]->$column = substr(trim($matches[$j+1]),1,-1); |
893 | } |
894 | } |
895 | } |
896 | } |
897 | if (isset($id->cst)) { |
898 | $rows = file($pkgdir.'/'.$id->cst); |
899 | $columns = scorm_get_aicc_columns($rows[0],'block'); |
900 | $regexp = scorm_forge_cols_regexp($columns->columns,'(.+)?,'); |
901 | for ($i=1;$i<count($rows);$i++) { |
902 | if (preg_match($regexp,$rows[$i],$matches)) { |
903 | for ($j=0;$j<count($columns->columns);$j++) { |
904 | if ($j != $columns->mastercol) { |
905 | $courses[$courseid]->elements[substr(trim($matches[$j+1]),1,-1)]->parent = substr(trim($matches[$columns->mastercol+1]),1,-1); |
906 | } |
907 | } |
908 | } |
909 | } |
910 | } |
911 | if (isset($id->ort)) { |
912 | $rows = file($pkgdir.'/'.$id->ort); |
913 | } |
914 | if (isset($id->pre)) { |
915 | $rows = file($pkgdir.'/'.$id->pre); |
916 | $columns = scorm_get_aicc_columns($rows[0],'structure_element'); |
917 | $regexp = scorm_forge_cols_regexp($columns->columns,'(.+),'); |
918 | for ($i=1;$i<count($rows);$i++) { |
919 | if (preg_match($regexp,$rows[$i],$matches)) { |
920 | $courses[$courseid]->elements[$columns->mastercol+1]->prerequisites = substr(trim($matches[1-$columns->mastercol+1]),1,-1); |
921 | } |
922 | } |
923 | } |
924 | if (isset($id->cmp)) { |
925 | $rows = file($pkgdir.'/'.$id->cmp); |
926 | } |
927 | } |
928 | //print_r($courses); |
5c1ac70c |
929 | |
930 | $oldscoes = get_records('scorm_scoes','scorm',$scormid); |
931 | |
e4aa175a |
932 | $launch = 0; |
933 | if (isset($courses)) { |
934 | foreach ($courses as $course) { |
935 | unset($sco); |
936 | $sco->identifier = $course->id; |
937 | $sco->scorm = $scormid; |
938 | $sco->organization = ''; |
939 | $sco->title = $course->title; |
940 | $sco->parent = '/'; |
941 | $sco->launch = ''; |
942 | $sco->scormtype = ''; |
5c1ac70c |
943 | |
e4aa175a |
944 | //print_r($sco); |
5c1ac70c |
945 | if (get_record('scorm_scoes','scorm',$scormid,'identifier',$sco->identifier)) { |
946 | $id = update_record('scorm_scoes',$sco); |
947 | unset($oldscoes[$id]); |
948 | } else { |
949 | $id = insert_record('scorm_scoes',$sco); |
950 | } |
951 | |
e4aa175a |
952 | if ($launch == 0) { |
953 | $launch = $id; |
954 | } |
955 | if (isset($course->elements)) { |
956 | foreach($course->elements as $element) { |
957 | unset($sco); |
958 | $sco->identifier = $element->system_id; |
959 | $sco->scorm = $scormid; |
960 | $sco->organization = $course->id; |
961 | $sco->title = $element->title; |
962 | if (strtolower($element->parent) == 'root') { |
963 | $sco->parent = '/'; |
964 | } else { |
965 | $sco->parent = $element->parent; |
966 | } |
967 | if (isset($element->file_name)) { |
968 | $sco->launch = $element->file_name; |
969 | $sco->scormtype = 'sco'; |
970 | } else { |
971 | $element->file_name = ''; |
972 | $sco->scormtype = ''; |
973 | } |
974 | if (!isset($element->prerequisites)) { |
975 | $element->prerequisites = ''; |
976 | } |
977 | $sco->prerequisites = $element->prerequisites; |
978 | if (!isset($element->max_time_allowed)) { |
979 | $element->max_time_allowed = ''; |
980 | } |
981 | $sco->maxtimeallowed = $element->max_time_allowed; |
982 | if (!isset($element->time_limit_action)) { |
983 | $element->time_limit_action = ''; |
984 | } |
985 | $sco->timelimitaction = $element->time_limit_action; |
986 | if (!isset($element->mastery_score)) { |
987 | $element->mastery_score = ''; |
988 | } |
989 | $sco->masteryscore = $element->mastery_score; |
990 | $sco->previous = 0; |
991 | $sco->next = 0; |
5c1ac70c |
992 | if ($oldscoid = scorm_array_search('identifier',$sco->identifier,$oldscoes)) { |
993 | $sco->id = $oldscoid; |
994 | $id = update_record('scorm_scoes',$sco); |
995 | unset($oldscoes[$oldscoid]); |
996 | } else { |
997 | $id = insert_record('scorm_scoes',$sco); |
998 | } |
e4aa175a |
999 | if ($launch==0) { |
1000 | $launch = $id; |
1001 | } |
1002 | } |
1003 | } |
1004 | } |
1005 | } |
5c1ac70c |
1006 | if (!empty($oldscoes)) { |
1007 | foreach($oldscoes as $oldsco) { |
1008 | delete_records('scorm_scoes','id',$oldsco->id); |
1009 | delete_records('scorm_scoes_track','scoid',$oldsco->id); |
1010 | } |
1011 | } |
e4aa175a |
1012 | set_field('scorm','version','AICC','id',$scormid); |
1013 | return $launch; |
1014 | } |
1015 | |
1016 | function scorm_get_resources($blocks) { |
5c1ac70c |
1017 | $resources = array(); |
e4aa175a |
1018 | foreach ($blocks as $block) { |
1019 | if ($block['name'] == 'RESOURCES') { |
1020 | foreach ($block['children'] as $resource) { |
1021 | if ($resource['name'] == 'RESOURCE') { |
1022 | $resources[addslashes($resource['attrs']['IDENTIFIER'])] = $resource['attrs']; |
1023 | } |
1024 | } |
1025 | } |
1026 | } |
1027 | return $resources; |
1028 | } |
1029 | |
1030 | function scorm_get_manifest($blocks,$scoes) { |
e4aa175a |
1031 | static $parents = array(); |
1032 | static $resources; |
1033 | |
1034 | static $manifest; |
1035 | static $organization; |
1036 | |
1037 | if (count($blocks) > 0) { |
1038 | foreach ($blocks as $block) { |
1039 | switch ($block['name']) { |
1040 | case 'METADATA': |
1041 | if (isset($block['children'])) { |
1042 | foreach ($block['children'] as $metadata) { |
1043 | if ($metadata['name'] == 'SCHEMAVERSION') { |
1044 | if (empty($scoes->version)) { |
1045 | if (isset($metadata['tagData']) && (preg_match("/^(1\.2)$|^(CAM )?(1\.3)$/",$metadata['tagData'],$matches))) { |
1046 | $scoes->version = 'SCORM_'.$matches[count($matches)-1]; |
1047 | } else { |
1048 | $scoes->version = 'SCORM_1.2'; |
1049 | } |
1050 | } |
1051 | } |
1052 | } |
1053 | } |
1054 | break; |
1055 | case 'MANIFEST': |
f69db63e |
1056 | $manifest = addslashes($block['attrs']['IDENTIFIER']); |
e4aa175a |
1057 | $organization = ''; |
1058 | $resources = array(); |
1059 | $resources = scorm_get_resources($block['children']); |
1060 | $scoes = scorm_get_manifest($block['children'],$scoes); |
1061 | if (count($scoes->elements) <= 0) { |
1062 | foreach ($resources as $item => $resource) { |
1063 | if (!empty($resource['HREF'])) { |
1064 | $sco = new stdClass(); |
1065 | $sco->identifier = $item; |
1066 | $sco->title = $item; |
1067 | $sco->parent = '/'; |
1068 | $sco->launch = addslashes($resource['HREF']); |
1069 | $sco->scormtype = addslashes($resource['ADLCP:SCORMTYPE']); |
1070 | $scoes->elements[$manifest][$organization][$item] = $sco; |
1071 | } |
1072 | } |
1073 | } |
1074 | break; |
1075 | case 'ORGANIZATIONS': |
1076 | if (!isset($scoes->defaultorg)) { |
1077 | $scoes->defaultorg = addslashes($block['attrs']['DEFAULT']); |
1078 | } |
1079 | $scoes = scorm_get_manifest($block['children'],$scoes); |
1080 | break; |
1081 | case 'ORGANIZATION': |
1082 | $identifier = addslashes($block['attrs']['IDENTIFIER']); |
1083 | $organization = ''; |
1084 | $scoes->elements[$manifest][$organization][$identifier]->identifier = $identifier; |
1085 | $scoes->elements[$manifest][$organization][$identifier]->parent = '/'; |
1086 | $scoes->elements[$manifest][$organization][$identifier]->launch = ''; |
1087 | $scoes->elements[$manifest][$organization][$identifier]->scormtype = ''; |
1088 | |
1089 | $parents = array(); |
1090 | $parent = new stdClass(); |
1091 | $parent->identifier = $identifier; |
1092 | $parent->organization = $organization; |
1093 | array_push($parents, $parent); |
1094 | $organization = $identifier; |
1095 | |
1096 | $scoes = scorm_get_manifest($block['children'],$scoes); |
1097 | |
1098 | array_pop($parents); |
1099 | break; |
1100 | case 'ITEM': |
1101 | $parent = array_pop($parents); |
1102 | array_push($parents, $parent); |
1103 | |
1104 | $identifier = addslashes($block['attrs']['IDENTIFIER']); |
1105 | $scoes->elements[$manifest][$organization][$identifier]->identifier = $identifier; |
1106 | $scoes->elements[$manifest][$organization][$identifier]->parent = $parent->identifier; |
1107 | if (!isset($block['attrs']['ISVISIBLE'])) { |
1108 | $block['attrs']['ISVISIBLE'] = 'true'; |
1109 | } |
1110 | $scoes->elements[$manifest][$organization][$identifier]->isvisible = addslashes($block['attrs']['ISVISIBLE']); |
1111 | if (!isset($block['attrs']['PARAMETERS'])) { |
1112 | $block['attrs']['PARAMETERS'] = ''; |
1113 | } |
1114 | $scoes->elements[$manifest][$organization][$identifier]->parameters = addslashes($block['attrs']['PARAMETERS']); |
1115 | if (!isset($block['attrs']['IDENTIFIERREF'])) { |
1116 | $scoes->elements[$manifest][$organization][$identifier]->launch = ''; |
1117 | $scoes->elements[$manifest][$organization][$identifier]->scormtype = 'asset'; |
1118 | } else { |
1119 | $idref = addslashes($block['attrs']['IDENTIFIERREF']); |
1120 | $base = ''; |
1121 | if (isset($resources[$idref]['XML:BASE'])) { |
1122 | $base = $resources[$idref]['XML:BASE']; |
1123 | } |
1124 | $scoes->elements[$manifest][$organization][$identifier]->launch = addslashes($base.$resources[$idref]['HREF']); |
1125 | if (empty($resources[$idref]['ADLCP:SCORMTYPE'])) { |
1126 | $resources[$idref]['ADLCP:SCORMTYPE'] = 'asset'; |
1127 | } |
1128 | $scoes->elements[$manifest][$organization][$identifier]->scormtype = addslashes($resources[$idref]['ADLCP:SCORMTYPE']); |
1129 | } |
5c1ac70c |
1130 | |
e4aa175a |
1131 | $parent = new stdClass(); |
1132 | $parent->identifier = $identifier; |
1133 | $parent->organization = $organization; |
1134 | array_push($parents, $parent); |
1135 | |
1136 | $scoes = scorm_get_manifest($block['children'],$scoes); |
1137 | |
1138 | array_pop($parents); |
1139 | break; |
1140 | case 'TITLE': |
1141 | $parent = array_pop($parents); |
1142 | array_push($parents, $parent); |
f69db63e |
1143 | if (!isset($block['tagData'])) { |
1144 | $block['tagData'] = ''; |
1145 | } |
e4aa175a |
1146 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->title = addslashes($block['tagData']); |
1147 | break; |
1148 | case 'ADLCP:PREREQUISITES': |
1149 | if ($block['attrs']['TYPE'] == 'aicc_script') { |
1150 | $parent = array_pop($parents); |
1151 | array_push($parents, $parent); |
f69db63e |
1152 | if (!isset($block['tagData'])) { |
1153 | $block['tagData'] = ''; |
1154 | } |
e4aa175a |
1155 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->prerequisites = addslashes($block['tagData']); |
1156 | } |
1157 | break; |
1158 | case 'ADLCP:MAXTIMEALLOWED': |
1159 | $parent = array_pop($parents); |
1160 | array_push($parents, $parent); |
f69db63e |
1161 | if (!isset($block['tagData'])) { |
1162 | $block['tagData'] = ''; |
1163 | } |
e4aa175a |
1164 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->maxtimeallowed = addslashes($block['tagData']); |
1165 | break; |
1166 | case 'ADLCP:TIMELIMITACTION': |
1167 | $parent = array_pop($parents); |
1168 | array_push($parents, $parent); |
f69db63e |
1169 | if (!isset($block['tagData'])) { |
1170 | $block['tagData'] = ''; |
1171 | } |
e4aa175a |
1172 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->timelimitaction = addslashes($block['tagData']); |
1173 | break; |
1174 | case 'ADLCP:DATAFROMLMS': |
1175 | $parent = array_pop($parents); |
1176 | array_push($parents, $parent); |
f69db63e |
1177 | if (!isset($block['tagData'])) { |
1178 | $block['tagData'] = ''; |
1179 | } |
e4aa175a |
1180 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->datafromlms = addslashes($block['tagData']); |
1181 | break; |
1182 | case 'ADLCP:MASTERYSCORE': |
1183 | $parent = array_pop($parents); |
1184 | array_push($parents, $parent); |
f69db63e |
1185 | if (!isset($block['tagData'])) { |
1186 | $block['tagData'] = ''; |
1187 | } |
e4aa175a |
1188 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->masteryscore = addslashes($block['tagData']); |
1189 | break; |
f69db63e |
1190 | // Added by Pham Minh Duc |
e4aa175a |
1191 | case 'ADLNAV:PRESENTATION': |
1192 | $parent = array_pop($parents); |
1193 | array_push($parents, $parent); |
1194 | foreach ($block['children'] as $adlnav) { |
f69db63e |
1195 | if ($adlnav['name'] == 'ADLNAV:NAVIGATIONINTERFACE') { |
1196 | foreach ($adlnav['children'] as $adlnavInterface) { |
1197 | if ($adlnavInterface['name'] == 'ADLNAV:HIDELMSUI') { |
1198 | if ($adlnavInterface['tagData'] == 'continue') { |
1199 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->next = 1; |
e4aa175a |
1200 | } |
f69db63e |
1201 | if ($adlnavInterface['tagData'] == 'previous') { |
1202 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->previous = 1; |
e4aa175a |
1203 | } |
1204 | } |
1205 | |
1206 | } |
e4aa175a |
1207 | } |
1208 | } |
1209 | break; |
e4aa175a |
1210 | case 'IMSSS:SEQUENCING': |
1211 | $parent = array_pop($parents); |
1212 | array_push($parents, $parent); |
1213 | foreach ($block['children'] as $sequencing) { |
f69db63e |
1214 | if ($sequencing['name']=='IMSSS:CONTROLMODE') { |
1215 | if ($sequencing['attrs']['CHOICE'] == 'false') { |
1216 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->choice = 0; |
e4aa175a |
1217 | } |
f69db63e |
1218 | if ($sequencing['attrs']['CHOICEEXIT'] == 'false') { |
1219 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->choiceexit = 0; |
e4aa175a |
1220 | } |
f69db63e |
1221 | if ($sequencing['attrs']['FLOW'] == 'true') { |
1222 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->flow = 1; |
e4aa175a |
1223 | } |
f69db63e |
1224 | if ($sequencing['attrs']['FORWARDONLY'] == 'true') { |
1225 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->forwardonly = 1; |
e4aa175a |
1226 | } |
f69db63e |
1227 | if ($sequencing['attrs']['USECURRENTATTEMPTOBJECTINFO'] == 'true') { |
1228 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->usecurrentattemptobjectinfo = 1; |
e4aa175a |
1229 | } |
f69db63e |
1230 | if ($sequencing['attrs']['USECURRENTATTEMPTPROGRESSINFO'] == 'true') { |
1231 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->usecurrentattemptprogressinfo = 1; |
e4aa175a |
1232 | } |
1233 | } |
f69db63e |
1234 | if ($sequencing['name']=='ADLSEQ:CONSTRAINEDCHOICECONSIDERATIONS') { |
1235 | if ($sequencing['attrs']['CONSTRAINCHOICE'] == 'true') { |
1236 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->constrainChoice = 1; |
e4aa175a |
1237 | } |
f69db63e |
1238 | if ($sequencing['attrs']['PREVENTACTIVATION'] == 'true') { |
1239 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->preventactivation = 1; |
e4aa175a |
1240 | } |
1241 | |
1242 | } |
f69db63e |
1243 | if ($sequencing['name']=='IMSSS:OBJECTIVES') { |
1244 | foreach ($sequencing['children'] as $objective) { |
1245 | if ($objective['name']=='IMSSS:PRIMARYOBJECTIVE') { |
1246 | foreach ($objective['children'] as $primaryobjective) { |
1247 | if ($primaryobjective['name']=='IMSSS:MINNORMALIZEDMEASURE') { |
1248 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->minnormalizedmeasure = $primaryobjective['tagData']; |
e4aa175a |
1249 | } |
1250 | } |
1251 | } |
1252 | } |
1253 | } |
f69db63e |
1254 | if ($sequencing['name']=='IMSSS:LIMITCONDITIONS') { |
1255 | if (!empty($sequencing['attrs']['ATTEMPTLIMIT'])) { |
1256 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->attemptLimit = $sequencing['attrs']['ATTEMPTLIMIT']; |
e4aa175a |
1257 | } |
f69db63e |
1258 | if (!empty($sequencing['attrs']['ATTEMPTABSOLUTEDURATIONLIMIT'])) { |
1259 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->attemptAbsoluteDurationLimit = $sequencing['attrs']['ATTEMPTABSOLUTEDURATIONLIMIT']; |
e4aa175a |
1260 | } |
1261 | } |
f69db63e |
1262 | if ($sequencing['name']=='IMSSS:ROLLUPRULES') { |
e4aa175a |
1263 | $rolluprules = array(); |
f69db63e |
1264 | if (!empty($sequencing['attrs']['ROLLUPOBJECTIVESATISFIED'])) { |
1265 | if ($sequencing['attrs']['ROLLUPOBJECTIVESATISFIED']== 'false') { |
1266 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->rollupobjectivesatisfied = 0; |
e4aa175a |
1267 | } |
1268 | } |
f69db63e |
1269 | if (!empty($sequencing['attrs']['ROLLUPPROGRESSCOMPLETION'])) { |
1270 | if ($sequencing['attrs']['ROLLUPPROGRESSCOMPLETION']== 'false') { |
1271 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->rollupprogresscompletion = 0; |
e4aa175a |
1272 | } |
1273 | } |
f69db63e |
1274 | if (!empty($sequencing['attrs']['OBJECTIVEMEASUREWEIGHT'])) { |
e4aa175a |
1275 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->objectivemeasureweight = $sequencing['attrs']['OBJECTIVEMEASUREWEIGHT']; |
1276 | } |
1277 | |
1278 | if (!empty($sequencing['children'])){ |
f69db63e |
1279 | foreach ($sequencing['children'] as $sequencingrolluprule) { |
1280 | if ($sequencingrolluprule['name']=='IMSSS:ROLLUPRULE' ) { |
e4aa175a |
1281 | $rolluprule = new stdClass(); |
f69db63e |
1282 | if ($sequencingrolluprule['attrs']['CHILDACTIVITYSET'] !=' ') { |
e4aa175a |
1283 | $rolluprule->childactivityset = $sequencingrolluprule['attrs']['CHILDACTIVITYSET']; |
f69db63e |
1284 | if (!empty($sequencingrolluprule['children'])) { |
1285 | foreach ($sequencingrolluprule['children'] as $rolluproleconditions) { |
1286 | if ($rolluproleconditions['name']=='IMSSS:ROLLUPCONDITIONS') { |
e4aa175a |
1287 | $conditions = array(); |
f69db63e |
1288 | if (!empty($rolluproleconditions['attrs']['conditionCombination'])) { |
1289 | $rolluprule->conditionCombination = $rolluproleconditions['attrs']['conditionCombination']; |
e4aa175a |
1290 | } |
f69db63e |
1291 | foreach ($rolluproleconditions['children'] as $rolluprulecondition) { |
1292 | if ($rolluprulecondition['name']=='IMSSS:ROLLUPCONDITION') { |
e4aa175a |
1293 | $condition = new stdClass(); |
f69db63e |
1294 | if (!empty($rolluprulecondition['attrs']['OPERATOR'])) { |
e4aa175a |
1295 | $condition->operator = $rolluprulecondition['attrs']['OPERATOR']; |
1296 | } |
f69db63e |
1297 | if (!empty($rolluprulecondition['attrs']['CONDITION'])) { |
e4aa175a |
1298 | $condition->condition = $rolluprulecondition['attrs']['CONDITION']; |
1299 | } |
f69db63e |
1300 | array_push($conditions,$condition); |
e4aa175a |
1301 | } |
e4aa175a |
1302 | } |
f69db63e |
1303 | $rolluprule->conditions = $conditions; |
e4aa175a |
1304 | } |
f69db63e |
1305 | if ($rolluproleconditions['name']=='IMSSS:ROLLUPACTION') { |
1306 | $rolluprule->rollupruleaction = $rolluproleconditions['attrs']['ACTION']; |
e4aa175a |
1307 | } |
1308 | } |
1309 | } |
e4aa175a |
1310 | } |
e4aa175a |
1311 | array_push($rolluprules, $rolluprule); |
e4aa175a |
1312 | } |
e4aa175a |
1313 | } |
1314 | } |
1315 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->rolluprules = $rolluprules; |
e4aa175a |
1316 | } |
e4aa175a |
1317 | |
f69db63e |
1318 | if ($sequencing['name']=='IMSSS:SEQUENCINGRULES') { |
e4aa175a |
1319 | $sequencingrules = array(); |
f69db63e |
1320 | foreach ($sequencing['children'] as $conditionrules) { |
1321 | if ($conditionrules['name']=='IMSSS:EXITCONDITIONRULE') { |
1322 | $sequencingrule = new stdClass(); |
1323 | if (!empty($conditionrules['children'])) { |
1324 | foreach ($conditionrules['children'] as $conditionrule) { |
1325 | if ($conditionrule['name']=='IMSSS:RULECONDITIONS') { |
1326 | $ruleconditions = array(); |
1327 | if (!empty($conditionrule['attrs']['conditionCombination'])) { |
e4aa175a |
1328 | $sequencingrule->conditionCombination = $conditionrule['attrs']['conditionCombination']; |
f69db63e |
1329 | } |
1330 | foreach ($conditionrule['children'] as $rulecondition) { |
1331 | if ($rulecondition['name']=='IMSSS:RULECONDITION') { |
1332 | $condition = new stdClass(); |
1333 | if (!empty($rulecondition['attrs']['OPERATOR'])) { |
1334 | $condition->operator = $rulecondition['attrs']['OPERATOR']; |
e4aa175a |
1335 | } |
f69db63e |
1336 | if (!empty($rulecondition['attrs']['CONDITION'])) { |
1337 | $condition->condition = $rulecondition['attrs']['CONDITION']; |
1338 | } |
1339 | if (!empty($rulecondition['attrs']['MEASURETHRESHOLD'])) { |
1340 | $condition->measurethreshold = $rulecondition['attrs']['MEASURETHRESHOLD']; |
1341 | } |
1342 | if (!empty($rulecondition['attrs']['REFERENCEDOBJECTIVE'])) { |
1343 | $condition->referencedobjective = $rulecondition['attrs']['REFERENCEDOBJECTIVE']; |
1344 | } |
1345 | array_push($ruleconditions,$condition); |
e4aa175a |
1346 | } |
e4aa175a |
1347 | } |
f69db63e |
1348 | $sequencingrule->ruleconditions = $ruleconditions; |
1349 | } |
1350 | if ($conditionrule['name']=='IMSSS:RULEACTION') { |
e4aa175a |
1351 | $sequencingrule->exitconditionruleaction = $conditionrule['attrs']['ACTION']; |
f69db63e |
1352 | } |
1353 | } |
1354 | } |
1355 | array_push($sequencingrules,$sequencingrule); |
1356 | } |
1357 | if ($conditionrules['name']=='IMSSS:PRECONDITIONRULE') { |
1358 | $sequencingrule = new stdClass(); |
1359 | if (!empty($conditionrules['children'])) { |
1360 | foreach ($conditionrules['children'] as $conditionrule) { |
1361 | if ($conditionrule['name']=='IMSSS:RULECONDITIONS') { |
1362 | $ruleconditions = array(); |
1363 | if (!empty($conditionrule['attrs']['conditionCombination'])) { |
1364 | $sequencingrule->conditionCombination = $conditionrule['attrs']['conditionCombination']; |
1365 | } |
1366 | foreach ($conditionrule['children'] as $rulecondition) { |
1367 | if ($rulecondition['name']=='IMSSS:RULECONDITION') { |
1368 | $condition = new stdClass(); |
1369 | if (!empty($rulecondition['attrs']['OPERATOR'])) { |
1370 | $condition->operator = $rulecondition['attrs']['OPERATOR']; |
1371 | } |
1372 | if (!empty($rulecondition['attrs']['CONDITION'])) { |
1373 | $condition->condition = $rulecondition['attrs']['CONDITION']; |
1374 | } |
1375 | if (!empty($rulecondition['attrs']['MEASURETHRESHOLD'])) { |
1376 | $condition->measurethreshold = $rulecondition['attrs']['MEASURETHRESHOLD']; |
1377 | } |
1378 | if (!empty($rulecondition['attrs']['REFERENCEDOBJECTIVE'])) { |
1379 | $condition->referencedobjective = $rulecondition['attrs']['REFERENCEDOBJECTIVE']; |
1380 | } |
1381 | array_push($ruleconditions,$condition); |
1382 | } |
e4aa175a |
1383 | } |
f69db63e |
1384 | $sequencingrule->ruleconditions = $ruleconditions; |
1385 | } |
1386 | if ($conditionrule['name']=='IMSSS:RULEACTION') { |
1387 | $sequencingrule->preconditionruleaction = $conditionrule['attrs']['ACTION']; |
e4aa175a |
1388 | } |
1389 | } |
f69db63e |
1390 | } |
1391 | array_push($sequencingrules,$sequencingrule); |
e4aa175a |
1392 | } |
f69db63e |
1393 | if ($conditionrules['name']=='IMSSS:POSTCONDITIONRULE') { |
e4aa175a |
1394 | $sequencingrule = new stdClass(); |
f69db63e |
1395 | if (!empty($conditionrules['children'])) { |
1396 | foreach ($conditionrules['children'] as $conditionrule) { |
e4aa175a |
1397 | if ($conditionrule['name']=='IMSSS:RULECONDITIONS'){ |
1398 | $ruleconditions = array(); |
1399 | if (!empty($conditionrule['attrs']['conditionCombination'])){ |
1400 | $sequencingrule->conditionCombination = $conditionrule['attrs']['conditionCombination']; |
1401 | } |
1402 | foreach ($conditionrule['children'] as $rulecondition){ |
1403 | if ($rulecondition['name']=='IMSSS:RULECONDITION'){ |
1404 | $condition = new stdClass(); |
1405 | if (!empty($rulecondition['attrs']['OPERATOR'])){ |
1406 | $condition->operator = $rulecondition['attrs']['OPERATOR']; |
1407 | } |
1408 | if (!empty($rulecondition['attrs']['CONDITION'])){ |
1409 | $condition->condition = $rulecondition['attrs']['CONDITION']; |
1410 | } |
1411 | if (!empty($rulecondition['attrs']['MEASURETHRESHOLD'])){ |
1412 | $condition->measurethreshold = $rulecondition['attrs']['MEASURETHRESHOLD']; |
1413 | } |
1414 | if (!empty($rulecondition['attrs']['REFERENCEDOBJECTIVE'])){ |
1415 | $condition->referencedobjective = $rulecondition['attrs']['REFERENCEDOBJECTIVE']; |
f69db63e |
1416 | } |
1417 | array_push($ruleconditions,$condition); |
e4aa175a |
1418 | } |
e4aa175a |
1419 | } |
f69db63e |
1420 | $sequencingrule->ruleconditions = $ruleconditions; |
e4aa175a |
1421 | } |
1422 | if ($conditionrule['name']=='IMSSS:RULEACTION'){ |
e4aa175a |
1423 | $sequencingrule->postconditionruleaction = $conditionrule['attrs']['ACTION']; |
e4aa175a |
1424 | } |
1425 | } |
f69db63e |
1426 | } |
1427 | array_push($sequencingrules,$sequencingrule); |
e4aa175a |
1428 | } |
f69db63e |
1429 | $scoes->elements[$manifest][$parent->organization][$parent->identifier]->sequencingrules = $sequencingrules; |
e4aa175a |
1430 | } |
1431 | } |
1432 | } |
e4aa175a |
1433 | break; |
f69db63e |
1434 | // End Add |
e4aa175a |
1435 | } |
1436 | } |
1437 | } |
e4aa175a |
1438 | return $scoes; |
1439 | } |
1440 | |
1441 | function scorm_parse_scorm($pkgdir,$scormid) { |
1442 | global $CFG; |
e4aa175a |
1443 | |
1444 | $launch = 0; |
1445 | $manifestfile = $pkgdir.'/imsmanifest.xml'; |
1446 | |
1447 | if (is_file($manifestfile)) { |
1448 | |
1449 | $xmlstring = file_get_contents($manifestfile); |
1450 | $objXML = new xml2Array(); |
1451 | $manifests = $objXML->parse($xmlstring); |
5c1ac70c |
1452 | // print_r($manifests); |
e4aa175a |
1453 | $scoes = new stdClass(); |
1454 | $scoes->version = ''; |
1455 | $scoes = scorm_get_manifest($manifests,$scoes); |
1456 | |
1457 | if (count($scoes->elements) > 0) { |
5c1ac70c |
1458 | $olditems = get_records('scorm_scoes','scorm',$scormid); |
e4aa175a |
1459 | foreach ($scoes->elements as $manifest => $organizations) { |
1460 | foreach ($organizations as $organization => $items) { |
1461 | foreach ($items as $identifier => $item) { |
1462 | $item->scorm = $scormid; |
1463 | $item->manifest = $manifest; |
1464 | $item->organization = $organization; |
5c1ac70c |
1465 | if ($olditemid = scorm_array_search('identifier',$item->identifier,$olditems)) { |
1466 | $item->id = $olditemid; |
1467 | $id = update_record('scorm_scoes',$item); |
1468 | unset($olditems[$olditemid]); |
1469 | } else { |
1470 | $id = insert_record('scorm_scoes',$item); |
1471 | } |
f69db63e |
1472 | // Added by Pham Minh Duc |
e4aa175a |
1473 | $item->scormid = $scormid; |
1474 | $item->scoid = $id; |
1475 | $idControlMode = insert_record('scorm_sequencing_controlmode',$item); |
1476 | |
f69db63e |
1477 | if (!empty($item->sequencingrules)) { |
1478 | foreach($item->sequencingrules as $sequencingrule) { |
e4aa175a |
1479 | $sequencingrule->scormid = $scormid; |
1480 | $sequencingrule->scoid = $item->scoid; |
e4aa175a |
1481 | $idruleconditions = insert_record('scorm_sequencing_ruleconditions',$sequencingrule); |
f69db63e |
1482 | foreach($sequencingrule->ruleconditions as $rulecondition) { |
e4aa175a |
1483 | $rulecondition->scormid = $sequencingrule->scormid; |
1484 | $rulecondition->scoid = $sequencingrule->scoid; |
1485 | $rulecondition->ruleconditionsid = $idruleconditions; |
1486 | $idrulecondition = insert_record('scorm_sequencing_rulecondition',$rulecondition); |
e4aa175a |
1487 | } |
e4aa175a |
1488 | } |
1489 | } |
1490 | |
f69db63e |
1491 | if (!empty($item->rolluprules)) { |
e4aa175a |
1492 | $idControlMode = insert_record('scorm_sequencing_rolluprules',$item); |
f69db63e |
1493 | foreach($item->rolluprules as $rollup) { |
e4aa175a |
1494 | $rollup->rolluprulesid =$idControlMode; |
1495 | $rollup->scormid = $scormid; |
1496 | $rollup->scoid = $item->scoid; |
1497 | |
e4aa175a |
1498 | $idRollupRule = insert_record('scorm_sequencing_rolluprule',$rollup); |
e4aa175a |
1499 | $rollup->rollupruleid = $idRollupRule; |
1500 | $idconditions = insert_record('scorm_sequencing_rollupruleconditions',$rollup); |
e4aa175a |
1501 | foreach($rollup->conditions as $condition){ |
1502 | $condition->ruleconditionsid = $idconditions; |
1503 | $condition->scormid = $rollup->scormid; |
1504 | $condition->scoid = $rollup->scoid; |
1505 | $idcondition = insert_record('scorm_sequencing_rolluprulecondition',$condition); |
e4aa175a |
1506 | } |
e4aa175a |
1507 | } |
1508 | } |
f69db63e |
1509 | // End Add |
e4aa175a |
1510 | if (($launch == 0) && ((empty($scoes->defaultorg)) || ($scoes->defaultorg == $identifier))) { |
1511 | $launch = $id; |
1512 | } |
1513 | } |
1514 | } |
1515 | } |
5c1ac70c |
1516 | if (!empty($olditems)) { |
1517 | foreach($olditems as $olditem) { |
1518 | delete_records('scorm_scoes','id',$olditem->id); |
1519 | delete_records('scorm_scoes_track','scoid',$olditem->id); |
1520 | } |
1521 | } |
e4aa175a |
1522 | set_field('scorm','version',$scoes->version,'id',$scormid); |
1523 | } |
1524 | } |
1525 | |
1526 | return $launch; |
1527 | } |
1528 | |
5c1ac70c |
1529 | function scorm_array_search($item, $needle, $haystacks, $strict=false) { |
1530 | if (!empty($haystacks)) { |
1531 | foreach ($haystacks as $key => $element) { |
1532 | if ($strict) { |
1533 | if ($element->{$item} === $needle) { |
1534 | return $key; |
1535 | } |
1536 | } else { |
1537 | if ($element->{$item} == $needle) { |
1538 | return $key; |
1539 | } |
1540 | } |
1541 | } |
1542 | } |
1543 | return false; |
1544 | } |
1545 | |
e4aa175a |
1546 | function scorm_course_format_display($user,$course) { |
1547 | global $CFG; |
1548 | |
1549 | $strupdate = get_string('update'); |
1550 | $strmodule = get_string('modulename','scorm'); |
1551 | |
1552 | echo '<div class="mod-scorm">'; |
1553 | if ($scorms = get_all_instances_in_course('scorm', $course)) { |
1554 | // The module SCORM activity with the least id is the course |
1555 | $scorm = current($scorms); |
1556 | if (! $cm = get_coursemodule_from_instance('scorm', $scorm->id, $course->id)) { |
1557 | error("Course Module ID was incorrect"); |
1558 | } |
1559 | $colspan = ''; |
1560 | $headertext = '<table width="100%"><tr><td class="title">'.get_string('name').': <b>'.format_string($scorm->name).'</b>'; |
1561 | if (isteacher($course->id, $user->id, true)) { |
1562 | if (isediting($course->id)) { |
1563 | // Display update icon |
1564 | $path = $CFG->wwwroot.'/course'; |
1565 | $headertext .= '<span class="commands">'. |
1566 | '<a title="'.$strupdate.'" href="'.$path.'/mod.php?update='.$cm->id.'&sesskey='.sesskey().'">'. |
1567 | '<img src="'.$CFG->pixpath.'/t/edit.gif" hspace="2" height="11" width="11" border="0" alt="'.$strupdate.'" /></a></span>'; |
1568 | } |
1569 | $headertext .= '</td>'; |
1570 | // Display report link |
1571 | $trackedusers = get_record('scorm_scoes_track', 'scormid', $scorm->id, '', '', '', '', 'count(distinct(userid)) as c'); |
1572 | if ($trackedusers->c > 0) { |
1573 | $headertext .= '<td class="reportlink">'. |
1574 | '<a target="'.$CFG->framename.'" href="'.$CFG->wwwroot.'/mod/scorm/report.php?id='.$cm->id.'">'. |
1575 | get_string('viewallreports','scorm',$trackedusers->c).'</a>'; |
1576 | } else { |
1577 | $headertext .= '<td class="reportlink">'.get_string('noreports','scorm'); |
1578 | } |
1579 | $colspan = ' colspan="2"'; |
1580 | } |
1581 | $headertext .= '</td></tr><tr><td'.$colspan.'>'.format_text(get_string('summary').':<br />'.$scorm->summary).'</td></tr></table>'; |
1582 | print_simple_box($headertext,'','100%'); |
1583 | scorm_view_display($user, $scorm, 'view.php?id='.$course->id, $cm, '100%'); |
1584 | } else { |
1585 | if (isteacheredit($course->id, $user->id)) { |
1586 | // Create a new activity |
1587 | redirect('mod.php?id='.$course->id.'&section=0&sesskey='.sesskey().'&add=scorm'); |
1588 | } else { |
1589 | notify('Could not find a scorm course here'); |
1590 | } |
1591 | } |
1592 | echo '</div>'; |
1593 | } |
1594 | |
1595 | function scorm_view_display ($user, $scorm, $action, $cm, $blockwidth='') { |
1596 | global $CFG; |
5c1ac70c |
1597 | |
e4aa175a |
1598 | $organization = optional_param('organization', '', PARAM_INT); |
1599 | |
1600 | print_simple_box_start('center',$blockwidth); |
1601 | ?> |
1602 | <div class="structurehead"><?php print_string('coursestruct','scorm') ?></div> |
1603 | <?php |
1604 | if (empty($organization)) { |
1605 | $organization = $scorm->launch; |
1606 | } |
1607 | if ($orgs = get_records_select_menu('scorm_scoes',"scorm='$scorm->id' AND organization='' AND launch=''",'id','id,title')) { |
1608 | if (count($orgs) > 1) { |
1609 | ?> |
1610 | <div class='center'> |
1611 | <?php print_string('organizations','scorm') ?> |
1612 | <form name='changeorg' method='post' action='<?php echo $action ?>'> |
1613 | <?php choose_from_menu($orgs, 'organization', "$organization", '','submit()') ?> |
1614 | </form> |
1615 | </div> |
1616 | <?php |
1617 | } |
1618 | } |
1619 | $orgidentifier = ''; |
1620 | if ($org = get_record('scorm_scoes','id',$organization)) { |
1621 | if (($org->organization == '') && ($org->launch == '')) { |
1622 | $orgidentifier = $org->identifier; |
1623 | } else { |
1624 | $orgidentifier = $org->organization; |
1625 | } |
1626 | } |
1627 | $result = scorm_get_toc($user,$scorm,'structlist',$orgidentifier); |
1628 | $incomplete = $result->incomplete; |
e4aa175a |
1629 | echo $result->toc; |
e4aa175a |
1630 | print_simple_box_end(); |
1631 | ?> |
1632 | <div class="center"> |
1633 | <form name="theform" method="post" action="<?php echo $CFG->wwwroot ?>/mod/scorm/player.php?id=<?php echo $cm->id ?>"<?php echo $scorm->popup == 1?' target="newwin"':'' ?>> |
1634 | <?php |
f69db63e |
1635 | // Added by Pham Minh Duc |
1636 | $suspend = get_record("scorm_suspendtrack","scormid",$scorm->id,"userid",$user->id); |
1637 | // End Add |
e4aa175a |
1638 | |
e4aa175a |
1639 | if ($scorm->hidebrowse == 0) { |
1640 | print_string("mode","scorm"); |
1641 | echo ': <input type="radio" id="b" name="mode" value="browse" /><label for="b">'.get_string('browse','scorm').'</label>'."\n"; |
1642 | if ($incomplete === true) { |
1643 | echo '<input type="radio" id="n" name="mode" value="normal" checked="checked" /><label for="n">'.get_string('normal','scorm')."</label>\n"; |
f69db63e |
1644 | // Added by Pham Minh Duc |
1645 | if (!empty($suspend)) { |
e4aa175a |
1646 | echo '<input type="radio" id="n" name="mode" value="continue" checked="checked" /><label for="n">'.get_string('continue','scorm')."</label>\n"; |
1647 | } |
f69db63e |
1648 | // End Add |
e4aa175a |
1649 | } else { |
1650 | echo '<input type="radio" id="r" name="mode" value="review" checked="checked" /><label for="r">'.get_string('review','scorm')."</label>\n"; |
1651 | } |
1652 | } else { |
1653 | if ($incomplete === true) { |
1654 | echo '<input type="hidden" name="mode" value="normal" />'."\n"; |
1655 | } else { |
1656 | echo '<input type="hidden" name="mode" value="review" />'."\n"; |
1657 | } |
1658 | } |
1659 | if (($incomplete === false) && (($result->attemptleft > 0)||($scorm->maxattempt == 0))) { |
1660 | ?> |
1661 | <br /> |
1662 | <input type="checkbox" id="a" name="newattempt" /> |
1663 | <label for="a"><?php print_string('newattempt','scorm') ?></label> |
1664 | <?php |
1665 | } |
1666 | ?> |
1667 | <br /> |
1668 | <input type="hidden" name="scoid" /> |
1669 | <input type="hidden" name="currentorg" value="<?php echo $orgidentifier ?>" /> |
1670 | <input type="submit" value="<?php print_string('entercourse','scorm') ?>" /> |
1671 | </form> |
1672 | </div> |
1673 | <?php |
1674 | } |
1675 | |
e4aa175a |
1676 | function scorm_repeater($what, $times) { |
1677 | if ($times <= 0) { |
1678 | return null; |
1679 | } |
1680 | $return = ''; |
1681 | for ($i=0; $i<$times;$i++) { |
1682 | $return .= $what; |
1683 | } |
1684 | return $return; |
1685 | } |
1686 | |
e4aa175a |
1687 | /* Usage |
1688 | Grab some XML data, either from a file, URL, etc. however you want. Assume storage in $strYourXML; |
1689 | |
1690 | $objXML = new xml2Array(); |
1691 | $arrOutput = $objXML->parse($strYourXML); |
1692 | print_r($arrOutput); //print it out, or do whatever! |
1693 | |
1694 | */ |
1695 | class xml2Array { |
1696 | |
1697 | var $arrOutput = array(); |
1698 | var $resParser; |
1699 | var $strXmlData; |
1700 | |
1701 | /** |
1702 | * Convert a utf-8 string to html entities |
1703 | * |
1704 | * @param string $str The UTF-8 string |
1705 | * @return string |
1706 | */ |
1707 | function utf8_to_entities($str) { |
f69db63e |
1708 | global $CFG; |
1709 | |
e4aa175a |
1710 | $entities = ''; |
1711 | $values = array(); |
1712 | $lookingfor = 1; |
1713 | |
f69db63e |
1714 | if (empty($CFG->unicodedb)) { // If Unicode DB support enable does not convert string |
1715 | $textlib = textlib_get_instance(); |
1716 | for ($i = 0; $i < $textlib->strlen($str,'utf-8'); $i++) { |
1717 | $thisvalue = ord($str[$i]); |
1718 | if ($thisvalue < 128) { |
1719 | $entities .= $str[$i]; // Leave ASCII chars unchanged |
1720 | } else { |
1721 | if (count($values) == 0) { |
1722 | $lookingfor = ($thisvalue < 224) ? 2 : 3; |
1723 | } |
1724 | $values[] = $thisvalue; |
1725 | if (count($values) == $lookingfor) { |
1726 | $number = ($lookingfor == 3) ? |
1727 | (($values[0] % 16) * 4096) + (($values[1] % 64) * 64) + ($values[2] % 64): |
1728 | (($values[0] % 32) * 64) + ($values[1] % 64); |
1729 | $entities .= '&#' . $number . ';'; |
1730 | $values = array(); |
1731 | $lookingfor = 1; |
1732 | } |
e4aa175a |
1733 | } |
1734 | } |
f69db63e |
1735 | return $entities; |
1736 | } else { |
1737 | return $str; |
e4aa175a |
1738 | } |
e4aa175a |
1739 | } |
1740 | |
1741 | /** |
1742 | * Parse an XML text string and create an array tree that rapresent the XML structure |
1743 | * |
1744 | * @param string $strInputXML The XML string |
1745 | * @return array |
1746 | */ |
1747 | function parse($strInputXML) { |
1748 | $this->resParser = xml_parser_create ('UTF-8'); |
1749 | xml_set_object($this->resParser,$this); |
1750 | xml_set_element_handler($this->resParser, "tagOpen", "tagClosed"); |
1751 | |
1752 | xml_set_character_data_handler($this->resParser, "tagData"); |
1753 | |
1754 | $this->strXmlData = xml_parse($this->resParser,$strInputXML ); |
1755 | if(!$this->strXmlData) { |
1756 | die(sprintf("XML error: %s at line %d", |
1757 | xml_error_string(xml_get_error_code($this->resParser)), |
1758 | xml_get_current_line_number($this->resParser))); |
1759 | } |
1760 | |
1761 | xml_parser_free($this->resParser); |
1762 | |
1763 | return $this->arrOutput; |
1764 | } |
1765 | |
1766 | function tagOpen($parser, $name, $attrs) { |
1767 | $tag=array("name"=>$name,"attrs"=>$attrs); |
1768 | array_push($this->arrOutput,$tag); |
1769 | } |
1770 | |
1771 | function tagData($parser, $tagData) { |
1772 | if(trim($tagData)) { |
1773 | if(isset($this->arrOutput[count($this->arrOutput)-1]['tagData'])) { |
1774 | $this->arrOutput[count($this->arrOutput)-1]['tagData'] .= $this->utf8_to_entities($tagData); |
1775 | } else { |
1776 | $this->arrOutput[count($this->arrOutput)-1]['tagData'] = $this->utf8_to_entities($tagData); |
1777 | } |
1778 | } |
1779 | } |
1780 | |
1781 | function tagClosed($parser, $name) { |
1782 | $this->arrOutput[count($this->arrOutput)-2]['children'][] = $this->arrOutput[count($this->arrOutput)-1]; |
1783 | array_pop($this->arrOutput); |
1784 | } |
1785 | |
1786 | } |
5c1ac70c |
1787 | |
1788 | // |
1789 | // Functions added by Pham Minh Duc |
1790 | // |
1791 | function scorm_get_score_from_parent($sco,$userid,$grademethod=VALUESCOES) { |
1792 | $scores = NULL; |
1793 | $scores->scoes = 0; |
1794 | $scores->values = 0; |
1795 | $scores->scaled = 0; |
1796 | $scores->max = 0; |
1797 | $scores->sum = 0; |
1798 | |
1799 | $scoes_total = 0; |
1800 | $scoes_count = 0; |
1801 | $attempt = scorm_get_last_attempt($sco->scorm, $userid); |
1802 | $scoes = get_records('scorm_scoes', 'parent', $sco->identifier); |
1803 | foreach ($scoes as $sco) |
1804 | { |
1805 | $scoes_total++; |
1806 | if ($userdata=scorm_get_tracks($sco->id, $userid,$attempt)) { |
1807 | if (($userdata->status == 'completed') || ($userdata->success_status == 'passed')) { |
1808 | $scoes_count++; |
1809 | } |
1810 | |
1811 | $scoreraw = $userdata->score_raw; |
1812 | if (!empty($userdata->score_raw)) { |
1813 | $scores->values++; |
1814 | $scores->sum += $userdata->score_raw; |
1815 | $scores->max = ($userdata->score_raw > $scores->max)?$userdata->score_raw:$scores->max; |
1816 | } |
1817 | if (!empty($userdata->score_scaled)) { |
1818 | $scores->scaled = $scores->scaled + $userdata->score_scaled; |
1819 | } |
1820 | } |
1821 | } |
1822 | if ($scoes_count > 0) { |
1823 | $scores->scaled = ($scores->scaled)/($scoes_count); |
1824 | } |
1825 | switch ($grademethod) { |
1826 | case VALUEHIGHEST: |
1827 | return $scores->max; |
1828 | break; |
1829 | case VALUEAVERAGE: |
1830 | if ($scores->values > 0) { |
1831 | return $scores->sum/$scores->values; |
1832 | } else { |
1833 | return 0; |
1834 | } |
1835 | break; |
1836 | case VALUESUM: |
1837 | return $scores->sum; |
1838 | break; |
1839 | case VALUESCOES: |
1840 | return $scores->scaled; |
1841 | break; |
1842 | } |
1843 | } |
1844 | |
1845 | function scorm_get_user_sco_count($scormid, $userid) { |
1846 | $scoes_count = 0; |
1847 | $attempt = scorm_get_last_attempt($current->scorm, $userid); |
1848 | $scoes = get_records('scorm_scoes', 'scorm', $scormid); |
1849 | |
1850 | foreach ($scoes as $sco) { |
1851 | if ($userdata=scorm_get_tracks($sco->id, $userid,$attempt)) { |
1852 | if (($userdata->status == 'completed') || ($userdata->success_status == 'passed')) { |
1853 | $scoes_count++; |
1854 | } |
1855 | } |
1856 | } |
1857 | return $scoes_count; |
1858 | } |
1859 | |
1860 | function scorm_grade_user_new($scoes, $userid, $grademethod=VALUESCOES) { |
1861 | $scores = NULL; |
1862 | $scores->scoes = 0; |
1863 | $scores->values = 0; |
1864 | $scores->scaled = 0; |
1865 | $scores->max = 0; |
1866 | $scores->sum = 0; |
1867 | |
1868 | if (!$scoes) { |
1869 | return ''; |
1870 | } |
1871 | $current = current($scoes); |
1872 | $attempt = scorm_get_last_attempt($current->scorm, $userid); |
1873 | foreach ($scoes as $sco) { |
1874 | if ($userdata=scorm_get_tracks($sco->id, $userid,$attempt)) { |
1875 | if (($userdata->status == 'completed') || ($userdata->success_status == 'passed')) { |
1876 | $scores->scoes++; |
1877 | } |
1878 | $scaled = $userdata->score_scaled; |
1879 | $scoreraw = $userdata->score_raw; |
1880 | if ($scaled ==0){ |
1881 | $scores->scaled = $scores->scaled / $scores->scoes; |
1882 | } |
1883 | if (!empty($userdata->score_raw)) { |
1884 | $scores->values++; |
1885 | $scores->sum += $userdata->score_raw; |
1886 | $scores->max = ($userdata->score_raw > $scores->max)?$userdata->score_raw:$scores->max; |
1887 | } |
1888 | if (!empty($scaled)) { |
1889 | $scores->scaled = (($scores->scaled) * ($scores->scoes-1) + $scaled)/($scores->scoes); |
1890 | } |
1891 | } |
1892 | } |
1893 | switch ($grademethod) { |
1894 | case VALUEHIGHEST: |
1895 | return $scores->max; |
1896 | break; |
1897 | case VALUEAVERAGE: |
1898 | if ($scores->values > 0) { |
1899 | return $scores->sum/$scores->values; |
1900 | } else { |
1901 | return 0; |
1902 | } |
1903 | break; |
1904 | case VALUESUM: |
1905 | return $scores->sum; |
1906 | break; |
1907 | case VALUESCOES: |
1908 | return $scores->scaled; |
1909 | break; |
1910 | } |
1911 | } |
1912 | |
1913 | function scorm_insert_statistic($statisticInput){ |
1914 | $id = null; |
1915 | if ($statistic = get_record_select('scorm_statistic',"userid='$statisticInput->userid' AND scormid='$statisticInput->scormid'")) { |
1916 | |
1917 | $statistic->durationtime = $statisticInput->duration; |
1918 | $statistic->accesstime = $statisticInput->accesstime; |
1919 | $statistic->status = $statisticInput->status; |
1920 | $statistic->attemptnumber = $statisticInput->attemptnumber; |
1921 | $id = update_record('scorm_statistic',$statistic); |
1922 | } else { |
1923 | $id = insert_record('scorm_statistic',$statisticInput); |
1924 | } |
1925 | return $id; |
1926 | } |
1927 | |
1928 | function scorm_insert_trackmodel($userid,$scormid,$scoid,$attempt) { |
1929 | $id = null; |
1930 | if ($suspendtrack = get_record_select('scorm_suspendtrack',"userid='$userid' AND scormid='$scormid'")) { |
1931 | $suspendtrack->suspendscoid = $scoid; |
1932 | $suspendtrack->attempt = $attempt; |
1933 | $id = update_record('scorm_suspendtrack',$suspendtrack); |
1934 | } else { |
1935 | $suspendtrack->scormid = $scormid; |
1936 | $suspendtrack->suspendscoid = $scoid; |
1937 | $suspendtrack->userid = $userid; |
1938 | $suspendtrack->attempt = $attempt; |
1939 | $id = insert_record('scorm_suspendtrack',$suspendtrack); |
1940 | } |
1941 | return $id; |
1942 | } |
1943 | |
1944 | function scorm_get_suspendscoid($scormid,$userid) { |
1945 | if ($sco = get_record("scorm_suspendtrack","scormid",$scormid,"userid",$userid)) { |
1946 | $suspendscoid = $sco->suspendscoid; |
1947 | return $suspendscoid; |
1948 | } else { |
1949 | return 0; |
1950 | } |
1951 | } |
1952 | |
1953 | function scorm_set_attempt($scoid,$userid) { |
1954 | if ($scormid = get_field('scorm_scoes','scorm','id',$scoid)) { |
1955 | $attempt = scorm_get_last_attempt($scormid,$userid); |
1956 | } else { |
1957 | $attempt = 1; |
1958 | } |
1959 | $scormtype = get_field('scorm_scoes','scormtype','id',$scoid) ; |
1960 | if ($scormtype == 'sco'){ |
1961 | $element = 'cmi.attempt_status'; |
1962 | $value = 'attempted'; |
1963 | scorm_insert_track($userid,$scormid,$scoid,$attempt,$element,$value); |
1964 | } |
1965 | } |
1966 | |
1967 | function scorm_get_AbsoluteTimeLimit($scoid){ |
1968 | $sco = get_record("scorm_scoes","id",$scoid); |
1969 | if (!empty($sco)){ |
1970 | return $sco->attemptAbsoluteDurationLimit; |
1971 | } |
1972 | return 0; |
1973 | } |
1974 | |
1975 | function scorm_update_status($scormid,$scoid) |
1976 | { |
1977 | |
1978 | } |
1979 | |
1980 | function scorm_get_nextsco($scormid,$scoid) |
1981 | { |
1982 | |
1983 | } |
1984 | |
1985 | function scorm_get_presco($scormid,$scoid) |
1986 | { |
1987 | |
1988 | } |
1989 | |
1990 | function scorm_isChoice($scormid,$scoid) |
1991 | { |
1992 | $sco = get_record("scorm_sequencing_controlmode","scormid",$scormid,"scoid",$scoid); |
1993 | $scoparent = get_record("scorm_sequencing_controlmode","scormid",$scormid,"identifier",$sco->parent); |
1994 | |
1995 | return $scoparent->choice; |
1996 | } |
1997 | |
1998 | function scorm_isChoiceexit($scormid,$scoid) |
1999 | { |
2000 | $sco = get_record("scorm_sequencing_controlmode","scormid",$scormid,"scoid",$scoid); |
2001 | $scoparent = get_record("scorm_sequencing_controlmode","scormid",$scormid,"identifier",$sco->parent); |
2002 | |
2003 | return $scoparent->choiceexit; |
2004 | } |
2005 | // End add |
e4aa175a |
2006 | ?> |