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