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