admin tree: MDL-13104 - fix another external page so there are not problems when...
[moodle.git] / mod / scorm / datamodels / aicclib.php
CommitLineData
f4ba7e1a 1<?php // $Id$
dc383b6f 2function scorm_add_time($a, $b) {
3 $aes = explode(':',$a);
4 $bes = explode(':',$b);
5 $aseconds = explode('.',$aes[2]);
6 $bseconds = explode('.',$bes[2]);
7 $change = 0;
8
9 $acents = 0; //Cents
10 if (count($aseconds) > 1) {
11 $acents = $aseconds[1];
12 }
13 $bcents = 0;
14 if (count($bseconds) > 1) {
15 $bcents = $bseconds[1];
16 }
17 $cents = $acents + $bcents;
18 $change = floor($cents / 100);
19 $cents = $cents - ($change * 100);
20 if (floor($cents) < 10) {
21 $cents = '0'. $cents;
22 }
23
24 $secs = $aseconds[0] + $bseconds[0] + $change; //Seconds
25 $change = floor($secs / 60);
26 $secs = $secs - ($change * 60);
27 if (floor($secs) < 10) {
28 $secs = '0'. $secs;
29 }
30
31 $mins = $aes[1] + $bes[1] + $change; //Minutes
32 $change = floor($mins / 60);
33 $mins = $mins - ($change * 60);
34 if ($mins < 10) {
35 $mins = '0' . $mins;
36 }
37
38 $hours = $aes[0] + $bes[0] + $change; //Hours
39 if ($hours < 10) {
40 $hours = '0' . $hours;
41 }
42
43 if ($cents != '0') {
44 return $hours . ":" . $mins . ":" . $secs . '.' . $cents;
45 } else {
46 return $hours . ":" . $mins . ":" . $secs;
47 }
48}
49
50/**
51* Take the header row of an AICC definition file
52* and returns sequence of columns and a pointer to
53* the sco identifier column.
54*
55* @param string $row AICC header row
56* @param string $mastername AICC sco identifier column
57* @return mixed
58*/
59function scorm_get_aicc_columns($row,$mastername='system_id') {
60 $tok = strtok(strtolower($row),"\",\n\r");
61 $result->columns = array();
62 $i=0;
63 while ($tok) {
64 if ($tok !='') {
65 $result->columns[] = $tok;
66 if ($tok == $mastername) {
67 $result->mastercol = $i;
68 }
69 $i++;
70 }
71 $tok = strtok("\",\n\r");
72 }
73 return $result;
74}
75
76/**
77* Given a colums array return a string containing the regular
78* expression to match the columns in a text row.
79*
80* @param array $column The header columns
81* @param string $remodule The regular expression module for a single column
82* @return string
83*/
84function scorm_forge_cols_regexp($columns,$remodule='(".*")?,') {
85 $regexp = '/^';
86 foreach ($columns as $column) {
87 $regexp .= $remodule;
88 }
89 $regexp = substr($regexp,0,-1) . '/';
90 return $regexp;
91}
92
9528568b 93
94function scorm_parse_aicc($scorm) {
bf347041 95 global $DB;
96
9528568b 97 if (!isset($scorm->cmid)) {
98 $cm = get_coursemodule_from_instance('scorm', $scorm->id);
99 $scorm->cmid = $cm->id;
100 }
101 $context = get_context_instance(COURSE_MODULE, $scorm->cmid);
102
103 $fs = get_file_storage();
104
105 $files = $fs->get_area_files($context->id, 'scorm_content', 0, '', false);
106
107
dc383b6f 108 $version = 'AICC';
109 $ids = array();
110 $courses = array();
111 $extaiccfiles = array('crs','des','au','cst','ort','pre','cmp');
9528568b 112
113 foreach ($files as $file) {
114 $filename = $file->get_filename();
115 $ext = substr($filename,strrpos($filename,'.'));
116 $extension = strtolower(substr($ext,1));
117 if (in_array($extension,$extaiccfiles)) {
118 $id = strtolower(basename($filename,$ext));
119 $ids[$id]->$extension = $file;
dc383b6f 120 }
dc383b6f 121 }
9528568b 122
dc383b6f 123 foreach ($ids as $courseid => $id) {
124 if (isset($id->crs)) {
9528568b 125 $rows = $id->crs->get_content();
126 foreach ($rows as $row) {
127 if (preg_match("/^(.+)=(.+)$/",$row,$matches)) {
128 switch (strtolower(trim($matches[1]))) {
129 case 'course_id':
130 $courses[$courseid]->id = trim($matches[2]);
131 break;
132 case 'course_title':
133 $courses[$courseid]->title = trim($matches[2]);
134 break;
135 case 'version':
136 $courses[$courseid]->version = 'AICC_'.trim($matches[2]);
137 break;
dc383b6f 138 }
139 }
140 }
141 }
142 if (isset($id->des)) {
9528568b 143 $rows = $id->des->get_content();
dc383b6f 144 $columns = scorm_get_aicc_columns($rows[0]);
145 $regexp = scorm_forge_cols_regexp($columns->columns);
146 for ($i=1;$i<count($rows);$i++) {
147 if (preg_match($regexp,$rows[$i],$matches)) {
148 for ($j=0;$j<count($columns->columns);$j++) {
149 $column = $columns->columns[$j];
150 $courses[$courseid]->elements[substr(trim($matches[$columns->mastercol+1]),1,-1)]->$column = substr(trim($matches[$j+1]),1,-1);
151 }
152 }
153 }
154 }
155 if (isset($id->au)) {
9528568b 156 $rows = $id->au->get_content();
dc383b6f 157 $columns = scorm_get_aicc_columns($rows[0]);
158 $regexp = scorm_forge_cols_regexp($columns->columns);
159 for ($i=1;$i<count($rows);$i++) {
160 if (preg_match($regexp,$rows[$i],$matches)) {
161 for ($j=0;$j<count($columns->columns);$j++) {
162 $column = $columns->columns[$j];
163 $courses[$courseid]->elements[substr(trim($matches[$columns->mastercol+1]),1,-1)]->$column = substr(trim($matches[$j+1]),1,-1);
164 }
165 }
166 }
167 }
168 if (isset($id->cst)) {
9528568b 169 $rows = $id->cst->get_content();
dc383b6f 170 $columns = scorm_get_aicc_columns($rows[0],'block');
171 $regexp = scorm_forge_cols_regexp($columns->columns,'(.+)?,');
172 for ($i=1;$i<count($rows);$i++) {
173 if (preg_match($regexp,$rows[$i],$matches)) {
174 for ($j=0;$j<count($columns->columns);$j++) {
175 if ($j != $columns->mastercol) {
176 $courses[$courseid]->elements[substr(trim($matches[$j+1]),1,-1)]->parent = substr(trim($matches[$columns->mastercol+1]),1,-1);
177 }
178 }
179 }
180 }
181 }
182 if (isset($id->ort)) {
9528568b 183 $rows = $id->ort->get_content();
f6520280 184 $columns = scorm_get_aicc_columns($rows[0],'course_element');
185 $regexp = scorm_forge_cols_regexp($columns->columns,'(.+)?,');
186 for ($i=1;$i<count($rows);$i++) {
187 if (preg_match($regexp,$rows[$i],$matches)) {
188 for ($j=0;$j<count($matches)-1;$j++) {
189 if ($j != $columns->mastercol) {
190 $courses[$courseid]->elements[substr(trim($matches[$j+1]),1,-1)]->parent = substr(trim($matches[$columns->mastercol+1]),1,-1);
191 }
192 }
193 }
194 }
dc383b6f 195 }
196 if (isset($id->pre)) {
9528568b 197 $rows = $id->pre->get_content();
dc383b6f 198 $columns = scorm_get_aicc_columns($rows[0],'structure_element');
199 $regexp = scorm_forge_cols_regexp($columns->columns,'(.+),');
200 for ($i=1;$i<count($rows);$i++) {
201 if (preg_match($regexp,$rows[$i],$matches)) {
202 $courses[$courseid]->elements[$columns->mastercol+1]->prerequisites = substr(trim($matches[1-$columns->mastercol+1]),1,-1);
203 }
204 }
205 }
206 if (isset($id->cmp)) {
9528568b 207 $rows = $id->cmp->get_content();
dc383b6f 208 }
209 }
210 //print_r($courses);
211
9528568b 212 $oldscoes = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id));
dc383b6f 213
214 $launch = 0;
215 if (isset($courses)) {
216 foreach ($courses as $course) {
531fa830 217 $sco = new object();
dc383b6f 218 $sco->identifier = $course->id;
9528568b 219 $sco->scorm = $scorm->id;
dc383b6f 220 $sco->organization = '';
221 $sco->title = $course->title;
222 $sco->parent = '/';
223 $sco->launch = '';
224 $sco->scormtype = '';
225
226 //print_r($sco);
9528568b 227 if ($ss = $DB->get_record('scorm_scoes', array('scorm'=>$scorm->id,'identifier'=>$sco->identifier))) {
bf347041 228 $id = $ss->id;
229 $DB->update_record('scorm_scoes',$sco);
dc383b6f 230 unset($oldscoes[$id]);
231 } else {
bf347041 232 $id = $DB->insert_record('scorm_scoes',$sco);
dc383b6f 233 }
234
235 if ($launch == 0) {
236 $launch = $id;
237 }
238 if (isset($course->elements)) {
239 foreach($course->elements as $element) {
240 unset($sco);
241 $sco->identifier = $element->system_id;
9528568b 242 $sco->scorm = $scorm->id;
dc383b6f 243 $sco->organization = $course->id;
244 $sco->title = $element->title;
f6520280 245
246 if (!isset($element->parent) || strtolower($element->parent) == 'root') {
dc383b6f 247 $sco->parent = '/';
248 } else {
249 $sco->parent = $element->parent;
250 }
251 if (isset($element->file_name)) {
252 $sco->launch = $element->file_name;
253 $sco->scormtype = 'sco';
f6520280 254 $sco->previous = 0;
255 $sco->next = 0;
256 $id = null;
257 if ($oldscoid = scorm_array_search('identifier',$sco->identifier,$oldscoes)) {
258 $sco->id = $oldscoid;
bf347041 259 $id = $DB->update_record('scorm_scoes',$sco);
260 $DB->delete_records('scorm_scoes_data', array('scoid'=>$oldscoid));
f6520280 261 unset($oldscoes[$oldscoid]);
262 } else {
bf347041 263 $id = $DB->insert_record('scorm_scoes',$sco);
f6520280 264 }
265 if (!empty($id)) {
266 unset($scodata);
267 $scodata->scoid = $id;
268 if (isset($element->web_launch)) {
269 $scodata->name = 'parameters';
270 $scodata->value = $element->web_launch;
bf347041 271 $dataid = $DB->insert_record('scorm_scoes_data',$scodata);
f6520280 272 }
273 if (isset($element->prerequisites)) {
274 $scodata->name = 'prerequisites';
275 $scodata->value = $element->prerequisites;
bf347041 276 $dataid = $DB->insert_record('scorm_scoes_data',$scodata);
f6520280 277 }
278 if (isset($element->max_time_allowed)) {
279 $scodata->name = 'max_time_allowed';
280 $scodata->value = $element->max_time_allowed;
bf347041 281 $dataid = $DB->insert_record('scorm_scoes_data',$scodata);
f6520280 282 }
283 if (isset($element->time_limit_action)) {
284 $scodata->name = 'time_limit_action';
285 $scodata->value = $element->time_limit_action;
bf347041 286 $dataid = $DB->insert_record('scorm_scoes_data',$scodata);
f6520280 287 }
288 if (isset($element->mastery_score)) {
289 $scodata->name = 'mastery_score';
290 $scodata->value = $element->mastery_score;
bf347041 291 $dataid = $DB->insert_record('scorm_scoes_data',$scodata);
f6520280 292 }
52005f34 293 if (isset($element->core_vendor)) {
294 $scodata->name = 'datafromlms';
295 $scodata->value = eregi_replace('<cr>', "\r\n", $element->core_vendor);
c6089d93 296 $dataid = $DB->insert_record('scorm_scoes_data',$scodata);
52005f34 297 }
f6520280 298 }
299 if ($launch==0) {
300 $launch = $id;
301 }
dc383b6f 302 }
303 }
304 }
305 }
306 }
307 if (!empty($oldscoes)) {
308 foreach($oldscoes as $oldsco) {
bf347041 309 $DB->delete_records('scorm_scoes', array('id'=>$oldsco->id));
310 $DB->delete_records('scorm_scoes_track', array('scoid'=>$oldsco->id));
dc383b6f 311 }
312 }
9528568b 313
314 $scorm->version = 'AICC';
315
316 $scorm->launch = $launch;
317
318 return true;
dc383b6f 319}
320
321function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='normal',$attempt='',$play=false) {
bf347041 322 global $CFG, $DB;
dc383b6f 323
dc383b6f 324 $strexpand = get_string('expcoll','scorm');
325 $modestr = '';
326 if ($mode == 'browse') {
327 $modestr = '&amp;mode='.$mode;
328 }
329 $scormpixdir = $CFG->modpixpath.'/scorm/pix';
330
331 $result = new stdClass();
f6520280 332 $result->toc = "<ul id='s0' class='$liststyle'>\n";
dc383b6f 333 $tocmenus = array();
334 $result->prerequisites = true;
335 $incomplete = false;
336
337 //
338 // Get the current organization infos
339 //
dc383b6f 340 if (!empty($currentorg)) {
bf347041 341 if (($organizationtitle = $DB->get_field('scorm_scoes','title', array('scorm'=>$scorm->id,'identifier'=>$currentorg))) != '') {
dc383b6f 342 $result->toc .= "\t<li>$organizationtitle</li>\n";
343 $tocmenus[] = $organizationtitle;
344 }
dc383b6f 345 }
346 //
347 // If not specified retrieve the last attempt number
348 //
349 if (empty($attempt)) {
350 $attempt = scorm_get_last_attempt($scorm->id, $user->id);
351 }
352 $result->attemptleft = $scorm->maxattempt - $attempt;
82605bea 353 if ($scoes = scorm_get_scoes($scorm->id, $currentorg)){
dc383b6f 354 //
355 // Retrieve user tracking data for each learning object
356 //
357 $usertracks = array();
358 foreach ($scoes as $sco) {
359 if (!empty($sco->launch)) {
82605bea 360 if ($usertrack = scorm_get_tracks($sco->id,$user->id,$attempt)) {
dc383b6f 361 if ($usertrack->status == '') {
362 $usertrack->status = 'notattempted';
363 }
364 $usertracks[$sco->identifier] = $usertrack;
365 }
366 }
367 }
368
369 $level=0;
370 $sublist=1;
371 $previd = 0;
372 $nextid = 0;
373 $findnext = false;
374 $parents[$level]='/';
375
82605bea 376 foreach ($scoes as $pos => $sco) {
f6520280 377 $isvisible = false;
bf347041 378 $sco->title = $sco->title;
82605bea 379 if (!isset($sco->isvisible) || (isset($sco->isvisible) && ($sco->isvisible == 'true'))) {
380 $isvisible = true;
f6520280 381 }
dc383b6f 382 if ($parents[$level]!=$sco->parent) {
383 if ($newlevel = array_search($sco->parent,$parents)) {
384 for ($i=0; $i<($level-$newlevel); $i++) {
385 $result->toc .= "\t\t</ul></li>\n";
386 }
387 $level = $newlevel;
388 } else {
389 $i = $level;
390 $closelist = '';
391 while (($i > 0) && ($parents[$level] != $sco->parent)) {
392 $closelist .= "\t\t</ul></li>\n";
393 $i--;
394 }
395 if (($i == 0) && ($sco->parent != $currentorg)) {
396 $style = '';
397 if (isset($_COOKIE['hide:SCORMitem'.$sco->id])) {
398 $style = ' style="display: none;"';
399 }
f6520280 400 $result->toc .= "\t\t<li><ul id='s$sublist' class='$liststyle'$style>\n";
dc383b6f 401 $level++;
402 } else {
403 $result->toc .= $closelist;
404 $level = $i;
405 }
406 $parents[$level]=$sco->parent;
407 }
408 }
f6520280 409 if ($isvisible) {
410 $result->toc .= "\t\t<li>";
411 }
9fb2de4e 412 if (isset($scoes[$pos+1])) {
413 $nextsco = $scoes[$pos+1];
414 } else {
415 $nextsco = false;
416 }
f6520280 417 $nextisvisible = false;
82605bea 418 if (!isset($nextsco->isvisible) || (isset($nextsco->isvisible) && ($nextsco->isvisible == 'true'))) {
419 $nextisvisible = true;
f6520280 420 }
421 if ($nextisvisible && ($nextsco !== false) && ($sco->parent != $nextsco->parent) && (($level==0) || (($level>0) && ($nextsco->parent == $sco->identifier)))) {
dc383b6f 422 $sublist++;
423 $icon = 'minus';
424 if (isset($_COOKIE['hide:SCORMitem'.$nextsco->id])) {
425 $icon = 'plus';
426 }
859e38fe 427 $result->toc .= '<a href="javascript:expandCollide(\'img'.$sublist.'\',\'s'.$sublist.'\','.$nextsco->id.');"><img id="img'.$sublist.'" src="'.$scormpixdir.'/'.$icon.'.gif" alt="'.$strexpand.'" title="'.$strexpand.'"/></a>';
f6520280 428 } else if ($isvisible) {
c8420afe 429 $result->toc .= '<img src="'.$scormpixdir.'/spacer.gif" alt="spacer" />';
dc383b6f 430 }
431 if (empty($sco->title)) {
432 $sco->title = $sco->identifier;
433 }
434 if (!empty($sco->launch)) {
f6520280 435 if ($isvisible) {
436 $startbold = '';
437 $endbold = '';
438 $score = '';
439 if (empty($scoid) && ($mode != 'normal')) {
440 $scoid = $sco->id;
530a61d5 441 }
f6520280 442 if (isset($usertracks[$sco->identifier])) {
443 $usertrack = $usertracks[$sco->identifier];
444 $strstatus = get_string($usertrack->status,'scorm');
445 if ($sco->scormtype == 'sco') {
446 $statusicon = '<img src="'.$scormpixdir.'/'.$usertrack->status.'.gif" alt="'.$strstatus.'" title="'.$strstatus.'" />';
447 } else {
448 $statusicon = '<img src="'.$scormpixdir.'/assetc.gif" alt="'.get_string('assetlaunched','scorm').'" title="'.get_string('assetlaunched','scorm').'" />';
449 }
530a61d5 450
f6520280 451 if (($usertrack->status == 'notattempted') || ($usertrack->status == 'incomplete') || ($usertrack->status == 'browsed')) {
452 $incomplete = true;
453 if ($play && empty($scoid)) {
454 $scoid = $sco->id;
455 }
456 }
457 if ($usertrack->score_raw != '') {
458 $score = '('.get_string('score','scorm').':&nbsp;'.$usertrack->score_raw.')';
459 }
460 $strsuspended = get_string('suspended','scorm');
461 if (isset($usertrack->{'cmi.core.exit'}) && ($usertrack->{'cmi.core.exit'} == 'suspend')) {
462 $statusicon = '<img src="'.$scormpixdir.'/suspend.gif" alt="'.$strstatus.' - '.$strsuspended.'" title="'.$strstatus.' - '.$strsuspended.'" />';
463 }
464 } else {
dc383b6f 465 if ($play && empty($scoid)) {
466 $scoid = $sco->id;
467 }
f6520280 468 $incomplete = true;
469 if ($sco->scormtype == 'sco') {
470 $statusicon = '<img src="'.$scormpixdir.'/notattempted.gif" alt="'.get_string('notattempted','scorm').'" title="'.get_string('notattempted','scorm').'" />';
471 } else {
472 $statusicon = '<img src="'.$scormpixdir.'/asset.gif" alt="'.get_string('asset','scorm').'" title="'.get_string('asset','scorm').'" />';
473 }
530a61d5 474 }
f6520280 475 if ($sco->id == $scoid) {
f6520280 476 $startbold = '<b>';
477 $endbold = '</b>';
478 $findnext = true;
82605bea 479 $shownext = isset($sco->next) ? $sco->next : 0;
480 $showprev = isset($sco->previous) ? $sco->previous : 0;
dc383b6f 481 }
dc383b6f 482
f6520280 483 if (($nextid == 0) && (scorm_count_launchable($scorm->id,$currentorg) > 1) && ($nextsco!==false) && (!$findnext)) {
484 if (!empty($sco->launch)) {
485 $previd = $sco->id;
486 }
dc383b6f 487 }
f6520280 488 if (empty($sco->prerequisites) || scorm_eval_prerequisites($sco->prerequisites,$usertracks)) {
489 if ($sco->id == $scoid) {
490 $result->prerequisites = true;
491 }
492 $url = $CFG->wwwroot.'/mod/scorm/player.php?a='.$scorm->id.'&amp;currentorg='.$currentorg.$modestr.'&amp;scoid='.$sco->id;
493 $result->toc .= $statusicon.'&nbsp;'.$startbold.'<a href="'.$url.'">'.format_string($sco->title).'</a>'.$score.$endbold."</li>\n";
494 $tocmenus[$sco->id] = scorm_repeater('&minus;',$level) . '&gt;' . format_string($sco->title);
495 } else {
496 if ($sco->id == $scoid) {
497 $result->prerequisites = false;
498 }
c852a628 499 $result->toc .= $statusicon.'&nbsp;'.format_string($sco->title)."</li>\n";
dc383b6f 500 }
dc383b6f 501 }
502 } else {
c852a628 503 $result->toc .= '&nbsp;'.format_string($sco->title)."</li>\n";
dc383b6f 504 }
505 if (($nextsco !== false) && ($nextid == 0) && ($findnext)) {
506 if (!empty($nextsco->launch)) {
507 $nextid = $nextsco->id;
508 }
509 }
510 }
511 for ($i=0;$i<$level;$i++) {
512 $result->toc .= "\t\t</ul></li>\n";
513 }
514
515 if ($play) {
f6520280 516 $sco = scorm_get_sco($scoid);
dc383b6f 517 $sco->previd = $previd;
518 $sco->nextid = $nextid;
519 $result->sco = $sco;
520 $result->incomplete = $incomplete;
521 } else {
522 $result->incomplete = $incomplete;
523 }
524 }
525 $result->toc .= "\t</ul>\n";
526 if ($scorm->hidetoc == 0) {
527 $result->toc .= '
f4ba7e1a 528 <script type="text/javascript">
529 //<![CDATA[
dc383b6f 530 function expandCollide(which,list,item) {
859e38fe 531 var el = document.ids ? document.ids[list] : document.getElementById ? document.getElementById(list) : document.all[list];
f6520280 532 which = which.substring(0,(which.length));
859e38fe 533 var el2 = document.ids ? document.ids[which] : document.getElementById ? document.getElementById(which) : document.all[which];
534 if (el.style.display != "none") {
535 el2.src = "'.$scormpixdir.'/plus.gif";
536 el.style.display=\'none\';
dc383b6f 537 new cookie("hide:SCORMitem" + item, 1, 356, "/").set();
538 } else {
859e38fe 539 el2.src = "'.$scormpixdir.'/minus.gif";
540 el.style.display=\'block\';
dc383b6f 541 new cookie("hide:SCORMitem" + item, 1, -1, "/").set();
542 }
543 }
f4ba7e1a 544 //]]>
dc383b6f 545 </script>'."\n";
546 }
547
548 $url = $CFG->wwwroot.'/mod/scorm/player.php?a='.$scorm->id.'&amp;currentorg='.$currentorg.$modestr.'&amp;scoid=';
549 $result->tocmenu = popup_form($url,$tocmenus, "tocmenu", $sco->id, '', '', '', true);
550
551 return $result;
552}
553
554?>