Clean up for role_assign()
[moodle.git] / mod / scorm / locallib.php
CommitLineData
e4aa175a 1<?php // $Id$
f69db63e 2
e4aa175a 3define("VALUESCOES",0);
4define("VALUEHIGHEST",1);
5define("VALUEAVERAGE",2);
6define("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*/
24function 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*/
49function 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*/
70function 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*/
105function 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
130function 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
137function 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
161function 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 315function 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 334function 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 382function 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 396function 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
441function scorm_count_launchable($scormid,$organization) {
442 return count_records_select('scorm_scoes',"scorm=$scormid AND organization='$organization' AND launch<>''");
443}
444
445function 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 = '&amp;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').':&nbsp;'.$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.'&amp;currentorg='.$currentorg.$modestr.'&amp;scoid='.$sco->id;
607 $result->toc .= '&nbsp;'.$startbold.'<a href="'.$url.'">'.format_string($sco->title).'</a>'.$score.$endbold."</li>\n";
608 $tocmenus[$sco->id] = scorm_repeater('&minus;',$level) . '&gt;' . format_string($sco->title);
609 } else {
610 $result->toc .= '&nbsp;'.$startbold.format_string($sco->title).$score.$endbold."</li>\n";
611 $tocmenus[$sco->id] = scorm_repeater('&minus;',$level) . '&gt;' . 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 .= '&nbsp;'.$sco->title."</li>\n";
619 }
620 } else {
621 $result->toc .= '&nbsp;'.$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.'&amp;currentorg='.$currentorg.$modestr.'&amp;scoid=';
669 $result->tocmenu = popup_form($url,$tocmenus, "tocmenu", $sco->id, '', '', '', true);
670
671 return $result;
672}
673
674function 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 685function 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
765function 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*/
798function 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*/
823function 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 832function 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
1016function 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
1030function 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
1441function 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 1529function 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 1546function 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.'&amp;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.'&amp;section=0&sesskey='.sesskey().'&amp;add=scorm');
1588 } else {
1589 notify('Could not find a scorm course here');
1590 }
1591 }
1592 echo '</div>';
1593}
1594
1595function 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 1676function 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*/
1695class 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//
1791function 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
1845function 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
1860function 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
1913function 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
1928function 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
1944function 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
1953function 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
1967function 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
1975function scorm_update_status($scormid,$scoid)
1976{
1977
1978}
1979
1980function scorm_get_nextsco($scormid,$scoid)
1981{
1982
1983}
1984
1985function scorm_get_presco($scormid,$scoid)
1986{
1987
1988}
1989
1990function 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
1998function 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?>