MDL-18148 - AICC compliance fixes from Martin Holden.
[moodle.git] / mod / scorm / aicc.php
1 <?php
3     //Content Type Header
4     header("Content-type: text/plain");
5     //Prevent Caching Headers
6     header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
7     header("Cache-Control: no-cache");
8     header("Pragma: no-cache");
10     require_once('../../config.php');
11     include_once('lib.php');
12     require_once('locallib.php');
13     require_once('datamodels/aicclib.php');
14         
15     foreach ($_POST as $key => $value)
16                 {
17                         $tempkey = strtolower($key);
18                         $_POST[$tempkey] = $value;
19         }
20     
21     $command = required_param('command', PARAM_ALPHA);
22     $sessionid = required_param('session_id', PARAM_ALPHANUM);
23     $aiccdata = optional_param('aicc_data', '', PARAM_RAW);
25     require_login();
27     if (!empty($command) && confirm_sesskey($sessionid)) {
28         $command = strtolower($command);
30         if (isset($SESSION->scorm_scoid)) {
31             $scoid = $SESSION->scorm_scoid;
32         } else {
33             print_error('cannotcallscript');
34         }
35         $mode = 'normal';
36         if (isset($SESSION->scorm_mode)) {
37             $mode = $SESSION->scorm_mode;
38         }
39         $status = 'Not Initialized';
40         if (isset($SESSION->scorm_status)) {
41             $status = $SESSION->scorm_status;
42         }
43         if (isset($SESSION->attempt)) {
44             $attempt = $SESSION->attempt;
45         } else {
46             $attempt = 1;
47         }
49         if ($sco = scorm_get_sco($scoid, SCO_ONLY)) {
50             if (!$scorm = $DB->get_record('scorm','id',$sco->scorm)) {
51                 print_error('cannotcallscript');
52             }
53         } else {
54             print_error('cannotcallscript');
55         }
57         if ($scorm = $DB->get_record('scorm','id',$sco->scorm)) {
58             switch ($command) {
59                 case 'getparam':
60                     if ($status == 'Not Initialized') {
61                         $SESSION->scorm_status = 'Running';
62                         $status = 'Running';
63                     }
64                     if ($status != 'Running') {
65                         echo "error=101\r\nerror_text=Terminated\r\n";
66                     } else {
67                         if ($usertrack=scorm_get_tracks($scoid,$USER->id,$attempt)) {
68                             $userdata = $usertrack;
69                         } else {
70                             $userdata->status = '';
71                             $userdata->score_raw = '';
72                         }
73                         $userdata->student_id = $USER->username;
74                         $userdata->student_name = $USER->lastname .', '. $USER->firstname;
75                         $userdata->mode = $mode;
76                         if ($userdata->mode == 'normal') {
77                             $userdata->credit = 'credit';
78                         } else {
79                             $userdata->credit = 'no-credit';
80                         }
82                         if ($sco = scorm_get_sco($scoid)) {
83                             $userdata->course_id = $sco->identifier;
84                             $userdata->datafromlms = isset($sco->datafromlms)?$sco->datafromlms:'';
85                             $userdata->mastery_score = isset($sco->mastery_score)?$sco->mastery_score:'';
86                             $userdata->max_time_allowed = isset($sco->max_time_allowed)?$sco->max_time_allowed:'';
87                             $userdata->time_limit_action = isset($sco->time_limit_action)?$sco->time_limit_action:'';
89                             echo "error=0\r\nerror_text=Successful\r\naicc_data=";
90                             echo "[Core]\r\n";
91                             echo 'Student_ID='.$userdata->student_id."\r\n";
92                             echo 'Student_Name='.$userdata->student_name."\r\n";
93                             if (isset($userdata->{'cmi.core.lesson_location'})) {
94                                 echo 'Lesson_Location='.$userdata->{'cmi.core.lesson_location'}."\r\n";
95                             } else {
96                                 echo 'Lesson_Location='."\r\n";
97                             }
98                             echo 'Credit='.$userdata->credit."\r\n";
99                             if (isset($userdata->status)) {
100                                 if ($userdata->status == '') {
101                                     $userdata->entry = ', ab-initio';
102                                 } else {
103                                     if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {
104                                         $userdata->entry = ', resume';
105                                     } else {
106                                         $userdata->entry = '';
107                                     }
108                                 }
109                             }
110                             if (isset($userdata->{'cmi.core.lesson_status'})) {
111                                 echo 'Lesson_Status='.$userdata->{'cmi.core.lesson_status'}.$userdata->entry."\r\n";
112                                 $SESSION->scorm_lessonstatus = $userdata->{'cmi.core.lesson_status'};
113                             } else {
114                                 echo 'Lesson_Status=not attempted'.$userdata->entry."\r\n";
115                                 $SESSION->scorm_lessonstatus = 'not attempted';
116                             }
117                             if (isset($userdata->{'cmi.core.score.raw'})) {
118                                 $max = '';
119                                 $min = '';
120                                 if (isset($userdata->{'cmi.core.score.max'}) && !empty($userdata->{'cmi.core.score.max'})) {
121                                     $max = ', '.$userdata->{'cmi.core.score.max'};
122                                     if (isset($userdata->{'cmi.core.score.min'}) && !empty($userdata->{'cmi.core.score.min'})) {
123                                         $min = ', '.$userdata->{'cmi.core.score.min'};
124                                     }
125                                 }
126                                 echo 'Score='.$userdata->{'cmi.core.score.raw'}.$max.$min."\r\n";
127                             } else {
128                                 echo 'Score='."\r\n";
129                             }
130                             if (isset($userdata->{'cmi.core.total_time'})) {
131                                 echo 'Time='.$userdata->{'cmi.core.total_time'}."\r\n";
132                             } else {
133                                 echo 'Time='.'00:00:00'."\r\n";
134                             }
135                             echo 'Lesson_Mode='.$userdata->mode."\r\n";
136                             if (isset($userdata->{'cmi.suspend_data'})) {
137                                 echo "[Core_Lesson]\r\n".rawurldecode($userdata->{'cmi.suspend_data'})."\r\n";
138                             } else {
139                                 echo "[Core_Lesson]\r\n";
140                             }
141                             echo "[Core_Vendor]\r\n".$userdata->datafromlms."\r\n";
142                             echo "[Evaluation]\r\nCourse_ID = {".$userdata->course_id."}\r\n";
143                             echo "[Student_Data]\r\n";
144                             echo 'Mastery_Score='.$userdata->mastery_score."\r\n";
145                             echo 'Max_Time_Allowed='.$userdata->max_time_allowed."\r\n";
146                             echo 'Time_Limit_Action='.$userdata->time_limit_action."\r\n";
147                         } else {
148                             print_error('cannotfindsco', 'scorm');
149                         }
150                     }
151                 break;
152                 case 'putparam':
153                     if ($status == 'Running') {
154                         if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $scorm->course)) {
155                             echo "error=1\r\nerror_text=Unknown\r\n"; // No one must see this error message if not hacked
156                         }
157                         if (!empty($aiccdata) && has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE, $cm->id))) {
158                             $initlessonstatus = 'not attempted';
159                             $lessonstatus = 'not attempted';
160                             if (isset($SESSION->scorm_lessonstatus)) {
161                                 $initlessonstatus = $SESSION->scorm_lessonstatus;
162                             }
163                             $score = '';
164                             $datamodel['lesson_location'] = 'cmi.core.lesson_location';
165                             $datamodel['lesson_status'] = 'cmi.core.lesson_status';
166                             $datamodel['score'] = 'cmi.core.score.raw';
167                             $datamodel['time'] = 'cmi.core.session_time';
168                             $datamodel['[core_lesson]'] = 'cmi.suspend_data';
169                             $datamodel['[comments]'] = 'cmi.comments';
170                             $datarows = explode("\r\n",$aiccdata);
171                             reset($datarows);
172                             while ((list(,$datarow) = each($datarows)) !== false) {
173                                 if (($equal = strpos($datarow, '=')) !== false) {
174                                     $element = strtolower(trim(substr($datarow,0,$equal)));
175                                     $value = trim(substr($datarow,$equal+1));
176                                     if (isset($datamodel[$element])) {
177                                         $element = $datamodel[$element];
178                                         switch ($element) {
179                                             case 'cmi.core.lesson_location':
180                                                 $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
181                                             break;
182                                             case 'cmi.core.lesson_status':
183                                                 $statuses = array(
184                                                            'passed' => 'passed',
185                                                            'completed' => 'completed',
186                                                            'failed' => 'failed',
187                                                            'incomplete' => 'incomplete',
188                                                            'browsed' => 'browsed',
189                                                            'not attempted' => 'not attempted',
190                                                            'p' => 'passed',
191                                                            'c' => 'completed',
192                                                            'f' => 'failed',
193                                                            'i' => 'incomplete',
194                                                            'b' => 'browsed',
195                                                            'n' => 'not attempted'
196                                                            );
197                                                 $exites = array(
198                                                            'logout' => 'logout',
199                                                            'time-out' => 'time-out',
200                                                            'suspend' => 'suspend',
201                                                            'l' => 'logout',
202                                                            't' => 'time-out',
203                                                            's' => 'suspend',
204                                                            );
205                                                 $values = explode(',',$value);
206                                                 $value = '';
207                                                 if (count($values) > 1) {
208                                                     $value = trim(strtolower($values[1]));
209                                                     $value = $value[0];
210                                                     if (isset($exites[$value])) {
211                                                         $value = $exites[$value];
212                                                     }
213                                                 }
214                                                 if (empty($value) || isset($exites[$value])) {
215                                                     $subelement = 'cmi.core.exit';
216                                                     $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);
217                                                 }
218                                                 $value = trim(strtolower($values[0]));
219                                                 $value = $value[0];
220                                                 if (isset($statuses[$value]) && ($mode == 'normal')) {
221                                                     $value = $statuses[$value];
222                                                     $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
223                                                 }
224                                                 $lessonstatus = $value;
225                                             break;
226                                             case 'cmi.core.score.raw':
227                                                  $values = explode(',',$value);
228                                                  if ((count($values) > 1) && ($values[1] >= $values[0]) && is_numeric($values[1])) {
229                                                      $subelement = 'cmi.core.score.max';
230                                                      $value = trim($values[1]);
231                                                      $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);
232                                                      if ((count($values) == 3) && ($values[2] <= $values[0]) && is_numeric($values[2])) {
233                                                          $subelement = 'cmi.core.score.min';
234                                                          $value = trim($values[2]);
235                                                          $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);
236                                                      }
237                                                  }
239                                                  $value = '';
240                                                  if (is_numeric($values[0])) {
241                                                      $value = trim($values[0]); 
242                                                      $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
243                                                  }
244                                                  $score = $value;
245                                             break;
246                                             case 'cmi.core.session_time':
247                                                  $SESSION->scorm_session_time = $value;
248                                             break;
249                                         }
250                                     }
251                                 } else {
252                                     if (isset($datamodel[strtolower(trim($datarow))])) {
253                                         $element = $datamodel[strtolower(trim($datarow))];
254                                         $value = '';
255                                         while ((($datarow = current($datarows)) !== false) && (substr($datarow,0,1) != '[')) {
256                                             $value .= $datarow."\r\n";
257                                             next($datarows);
258                                         }
259                                         $value = rawurlencode(stripslashes($value));
260                                         $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
261                                     }
262                                 }
263                             }
264                             if (($mode == 'browse') && ($initlessonstatus == 'not attempted')){
265                                 $lessonstatus = 'browsed';
266                                 $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', 'browsed');
267                             }
268                             if ($mode == 'normal') {
269                                 if ($lessonstatus == 'completed') {
270                                     if ($sco = scorm_get_sco($scoid)) {
271                                         if (!empty($sco->mastery_score) && !empty($score) && ($score >= $sco->mastery_score)) {
272                                             $lessonstatus = 'passed';
273                                         } else {
274                                             $lessonstatus = 'failed';
275                                         }
276                                         $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', $lessonstatus);
277                                     }
278                                 }
279                             }
280                         }
281                         echo "error=0\r\nerror_text=Successful\r\n";
282                     } else if ($status == 'Terminated') {
283                         echo "error=1\r\nerror_text=Terminated\r\n";
284                     } else {
285                         echo "error=1\r\nerror_text=Not Initialized\r\n";
286                     }
287                 break;
288                 case 'putcomments':
289                     if ($status == 'Running') {
290                         echo "error=0\r\nerror_text=Successful\r\n";
291                     } else if ($status == 'Terminated') {
292                         echo "error=1\r\nerror_text=Terminated\r\n";
293                     } else {
294                         echo "error=1\r\nerror_text=Not Initialized\r\n";
295                     }
296                 break;
297                 case 'putinteractions':
298                     if ($status == 'Running') {
299                         echo "error=0\r\nerror_text=Successful\r\n";
300                     } else if ($status == 'Terminated') {
301                         echo "error=1\r\nerror_text=Terminated\r\n";
302                     } else {
303                         echo "error=1\r\nerror_text=Not Initialized\r\n";
304                     }
305                 break;
306                 case 'putobjectives':
307                     if ($status == 'Running') {
308                         echo "error=0\r\nerror_text=Successful\r\n";
309                     } else if ($status == 'Terminated') {
310                         echo "error=1\r\nerror_text=Terminated\r\n";
311                     } else {
312                         echo "error=1\r\nerror_text=Not Initialized\r\n";
313                     }
314                 break;
315                 case 'putpath':
316                     if ($status == 'Running') {
317                         echo "error=0\r\nerror_text=Successful\r\n";
318                     } else if ($status == 'Terminated') {
319                         echo "error=1\r\nerror_text=Terminated\r\n";
320                     } else {
321                         echo "error=1\r\nerror_text=Not Initialized\r\n";
322                     }
323                 break;
324                 case 'putperformance':
325                     if ($status == 'Running') {
326                         echo "error=0\r\nerror_text=Successful\r\n";
327                     } else if ($status == 'Terminated') {
328                         echo "error=1\r\nerror_text=Terminated\r\n";
329                     } else {
330                         echo "error=1\r\nerror_text=Not Initialized\r\n";
331                     }
332                 break;
333                 case 'exitau':
334                     if ($status == 'Running') {
335                         if (isset($SESSION->scorm_session_time) && ($SESSION->scorm_session_time != '')) {
336                             if ($track = $DB->get_record_select('scorm_scoes_track',"userid='$USER->id' AND scormid='$scorm->id' AND scoid='$sco->id' AND element='cmi.core.total_time'")) {
337                                // Add session_time to total_time
338                                 $value = scorm_add_time($track->value, $SESSION->scorm_session_time);
339                                 $track->value = $value;
340                                 $track->timemodified = time();
341                                 $id = $DB->update_record('scorm_scoes_track',$track);
342                             } else {
343                                 $track->userid = $USER->id;
344                                 $track->scormid = $scorm->id;
345                                 $track->scoid = $sco->id;
346                                 $track->element = 'cmi.core.total_time';
347                                 $track->value = $SESSION->scorm_session_time;
348                                 $track->timemodified = time();
349                                 $id = $DB->insert_record('scorm_scoes_track',$track);
350                             }
351                         }
352                         $SESSION->scorm_status = 'Terminated';
353                         $SESSION->scorm_session_time = '';
354                         echo "error=0\r\nerror_text=Successful\r\n";
355                     } else if ($status == 'Terminated') {
356                         echo "error=1\r\nerror_text=Terminated\r\n";
357                     } else {
358                         echo "error=1\r\nerror_text=Not Initialized\r\n";
359                     }
360                 break;
361                 default:
362                     echo "error=1\r\nerror_text=Invalid Command\r\n";
363                 break;
364             }
365         }
366     } else {
367         if (empty($command)) {
368             echo "error=1\r\nerror_text=Invalid Command\r\n";
369         } else {
370             echo "error=3\r\nerror_text=Invalid Session ID\r\n";
371         }
372     }
373 ?>