ILIAS  release_8 Revision v8.24
class.ilSCORM13PlayerGUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
29{
30 public const ENABLE_GZIP = 0;
31
32 public const NONE = 0;
33 public const READONLY = 1;
34 public const WRITEONLY = 2;
35 public const READWRITE = 3;
36
40 private static array $schema = array // order of entries matters!
41 (
42 'package' => array(
43 'user_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'user_id'),
44 'learner_name' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'learner_name'),
45 'slm_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'slm_id'),
46 'mode' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'c_mode'),
47 'credit' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'credit'),
48 ),
49 'node' => array(
50 'accesscount' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'accesscount'),
51 'accessduration' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'accessduration'),
52 'accessed' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'accessed'),
53 'activityAbsoluteDuration' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'activityabsduration'),
54 'activityAttemptCount' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'activityattemptcount'),
55 'activityExperiencedDuration' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'activityexpduration'),
56 'activityProgressStatus' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'activityprogstatus'),
57 'attemptAbsoluteDuration' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'attemptabsduration'),
58 'attemptCompletionAmount' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'attemptcomplamount'),
59 'attemptCompletionStatus' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'attemptcomplstatus'),
60 'attemptExperiencedDuration' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'attemptexpduration'),
61 'attemptProgressStatus' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'attemptprogstatus'),
62 'audio_captioning' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'audio_captioning'),
63 'audio_level' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'audio_level'),
64 'availableChildren' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'availablechildren'),
65 'cmi_node_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cmi_node_id'),
66 'completion' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'completion'),
67 'completion_status' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'completion_status'),
68 'completion_threshold' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'completion_threshold'),
69 'cp_node_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cp_node_id'),
70 'created' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'created'),
71 'credit' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'credit'),
72 'delivery_speed' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'delivery_speed'),
73 'entry' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_entry'),
74 'exit' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_exit'),
75 'language' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_language'),
76 'launch_data' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'launch_data'),
77 'learner_name' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'learner_name'),
78 'location' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'location'),
79 'max' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_max'),
80 'min' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_min'),
81 'mode' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_mode'),
82 'modified' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'modified'),
83 'progress_measure' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'progress_measure'),
84 'raw' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_raw'),
85 'scaled' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'scaled'),
86 'scaled_passing_score' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'scaled_passing_score'),
87 'session_time' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'session_time'),
88 'success_status' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'success_status'),
89 'suspend_data' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'suspend_data'),
90 'total_time' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'total_time'),
91 'user_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'user_id'),
92 ),
93 'comment' => array(
94 'cmi_comment_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cmi_comment_id'),
95 'cmi_node_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cmi_node_id'),
96 'comment' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_comment'),
97 'timestamp' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_timestamp'),
98 'location' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'location'),
99 'sourceIsLMS' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'sourceislms'),
100 ),
101 'correct_response' => array(
102 'cmi_correct_response_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cmi_correct_resp_id'),
103 'cmi_interaction_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cmi_interaction_id'),
104 'pattern' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'pattern'),
105 ),
106 'interaction' => array(
107 'cmi_interaction_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cmi_interaction_id'),
108 'cmi_node_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cmi_node_id'),
109 'description' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'description'),
110 'id' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'id'),
111 'latency' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'latency'),
112 'learner_response' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'learner_response'),
113 'result' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'result'),
114 'timestamp' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_timestamp'),
115 'type' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_type'),
116 'weighting' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'weighting'),
117 ),
118 'objective' => array(
119 'cmi_interaction_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cmi_interaction_id'),
120 'cmi_node_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cmi_node_id'),
121 'cmi_objective_id' => array('pattern' => null, 'permission' => self::NONE, 'default' => null, 'dbfield' => 'cmi_objective_id'),
122 'completion_status' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'completion_status'),
123 'description' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'description'),
124 'id' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'id'),
125 'max' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_max'),
126 'min' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_min'),
127 'raw' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'c_raw'),
128 'scaled' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'scaled'),
129 'progress_measure' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'progress_measure'),
130 'success_status' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'success_status'),
131 'scope' => array('pattern' => null, 'permission' => self::READWRITE, 'default' => null, 'dbfield' => 'scope'),
132 ),
133 );
134
135 private int $userId;
136 public int $packageId;
137 public bool $jsMode;
138
141 public int $ref_id;
142 public ilCtrl $ctrl;
143 protected ilLanguage $lng;
144 protected string $page = "";
145
146 public function __construct()
147 {
148 global $DIC;
149 $this->ctrl = $DIC->ctrl();
150 $this->userId = $DIC->user()->getId();
151 $this->lng = $DIC->language();
152
153 // $this->packageId = (int) $_REQUEST['packageId'];
154 $this->jsMode = strpos($_SERVER['HTTP_ACCEPT'], 'text/javascript') !== false;
155
156 if ($DIC->http()->wrapper()->query()->has('page')) {
157 $this->page = $DIC->http()->wrapper()->query()->retrieve('page', $DIC->refinery()->kindlyTo()->string());
158 }
159
160 $this->ref_id = $DIC->http()->wrapper()->query()->retrieve('ref_id', $DIC->refinery()->kindlyTo()->int());
161 $this->slm = new ilObjSCORM2004LearningModule($this->ref_id, true);
162
163 $this->packageId = ilObject::_lookupObjectId($this->ref_id);
164 }
165
169 public function executeCommand(): void
170 {
171 global $DIC;
172 $ilAccess = $DIC->access();
173 $lng = $DIC->language();
174 $ilErr = $DIC['ilErr'];
175
176 $next_class = $this->ctrl->getNextClass($this);
177 $cmd = $this->ctrl->getCmd();
178
179 if (!$ilAccess->checkAccess("read", "", $this->ref_id)) {
180 $ilErr->raiseError($lng->txt("permission_denied"), $ilErr->WARNING);
181 }
182
183 $nodeId = 0;
184 if ($DIC->http()->wrapper()->query()->has('node_id')) {
185 $nodeId = $DIC->http()->wrapper()->query()->retrieve('node_id', $DIC->refinery()->kindlyTo()->int());
186 }
187
188
189 //$ilLog->write("SCORM2004 Player cmd: ".$cmd);
190
191 switch ($cmd) {
192
193 case 'getRTEjs':
194 $this->getRTEjs();
195 break;
196
197 case 'cp':
198 $this->getCPData();
199 break;
200
201 case 'adlact':
202 $this->getADLActData();
203 break;
204
205 case 'suspend':
206 $this->suspendADLActData();
207 break;
208
209 case 'getSuspend':
210 $this->getSuspendData();
211 break;
212
213 case 'gobjective':
214 // $this->writeGObjective();
215 break;
216
217 case 'getGobjective':
218 $this->readGObjective();
219 break;
220
221 case 'getSharedData':
222 $this->readSharedData($nodeId);
223 break;
224
225 case 'setSharedData':
226 $this->writeSharedData($nodeId);
227 break;
228
229 case 'cmi':
230
231 if ($_SERVER['REQUEST_METHOD'] === 'POST') {
233 $this->packageId,
234 $this->ref_id,
235 $this->slm->getDefaultLessonMode(),
236 $this->slm->getComments(),
237 $this->slm->getInteractions(),
238 $this->slm->getObjectives(),
239 $this->slm->getTime_from_lms(),
240 null,
241 $this->userId
242 );
243 //error_log("Saved CMI Data");
244 } else {
245 $this->fetchCMIData();
246 }
247 break;
248
249 case 'specialPage':
250 $this->specialPage();
251 break;
252
253 case 'debugGUI':
254 $this->debugGUI();
255 break;
256 case 'postLogEntry':
257 $this->postLogEntry();
258 break;
259 case 'liveLogContent':
260 $this->liveLogContent();
261 break;
262 case 'downloadLog':
263 $this->downloadLog();
264 break;
265 case 'openLog':
266 $this->openLog();
267 break;
268
269 case 'pingSession':
270 $this->pingSession();
271 break;
272 case 'scormPlayerUnload':
273 ilSCORM2004StoreData::scormPlayerUnload($this->packageId, $this->ref_id, $this->slm->getTime_from_lms(), $this->userId);
274 break;
275
276 // case 'getConfigForPlayer':
277 // $this->getConfigForPlayer();
278 // break;
279 default:
280 $this->getPlayer();
281 break;
282 }
283 }
284
285 public function getRTEjs(): void
286 {
287 $js_data = file_get_contents("./Modules/Scorm2004/scripts/buildrte/rte.js");
288 if (self::ENABLE_GZIP == 1) {
289 ob_start("ob_gzhandler");
290 header('Content-Type: text/javascript; charset=UTF-8');
291 } else {
292 header('Content-Type: text/javascript; charset=UTF-8');
293 }
294 echo $js_data;
295 }
296
297
298 public function getDataDirectory(): string
299 {
300 $webdir = str_replace("/ilias.php", "", $_SERVER["SCRIPT_NAME"]);
301 //load ressources always with absolute URL..relative URLS fail on innersco navigation on certain browsers
302 $lm_dir = $webdir . "/" . ILIAS_WEB_DIR . "/" . CLIENT_ID . "/lm_data" . "/lm_" . (string) $this->packageId;
303 return $lm_dir;
304 }
305
306 //config data also used for SOP
310 public function getConfigForPlayer(): array
311 {
312 global $DIC;
313 $ilUser = $DIC->user();
314
315 $initSuspendData = null;
316 $config = array(
317 'scope' => $this->getScope(),
318 'learner_id' => (string) $ilUser->getID(),
319 'cmi_learner_id' => (string) $this->slm->getApiStudentId(),
320 'course_id' => (string) $this->packageId,
321 'learner_name' => (string) $this->slm->getApiStudentName(),
322 'mode' => $this->slm->getDefaultLessonMode(),
323 'credit' => $this->slm->getCreditMode(),
324 'auto_review' => $this->slm->getAutoReviewChar(),
325 'hide_navig' => $this->slm->getHideNavig(),
326 'hide_menu' => $this->slm->getNoMenu(),
327 'ie_force_render' => $this->slm->getIe_force_render(),
328 'fourth_edition' => $this->slm->getFourth_edition(),
329 'sequencing_enabled' => $this->slm->getSequencing(),
330 'interactions_storable' => $this->slm->getInteractions(),
331 'objectives_storable' => $this->slm->getObjectives(),
332 'comments_storable' => $this->slm->getComments(),
333 'time_from_lms' => $this->slm->getTime_from_lms(),
334 'auto_last_visited' => $this->slm->getAuto_last_visited(),
335 'lesson_mastery_score' => $this->slm->getMasteryScore(),
336 'checkSetValues' => $this->slm->getCheck_values(),
337 'auto_suspend' => $this->slm->getAutoSuspend(),
338 'suspend_data' => $initSuspendData,
339 'cp_data' => null,
340 'cmi_data' => null,
341 'adlact_data' => null,
342 'globalobj_data' => null
343 );
344 $config['status'] = ilObjSCORMInitData::getStatus($this->packageId, $ilUser->getID(), $this->slm->getAuto_last_visited(), "2004");
345 // $status['last_visited']=null;
346 // if($this->slm->getAuto_last_visited())
347 // {
348 // $status['last_visited']=$this->get_last_visited($this->packageId, $ilUser->getID());
349 // }
350 // $config['status'] = $status;
351
352 return $config;
353 }
354
355 public function getPlayer(): void
356 {
357 global $DIC;
358 $lng = $DIC->language();
359 $ilSetting = $DIC->settings();
360 ilWACSignedPath::signFolderOfStartFile($this->getDataDirectory() . '/imsmanifest.xml');
361
362 // player basic config data
363
364 $initSuspendData = null;
365 $initAdlactData = null;
366 $initGlobalobjData = null;
367 if ($this->slm->getSequencing() == true) {
368 $initSuspendData = json_decode($this->getSuspendDataInit());
369 $initAdlactData = json_decode($this->getADLActDataInit());
370 $initGlobalobjData = $this->readGObjectiveInit();
371 }
372
373 $config = $this->getConfigForPlayer();
374
375 //session
376 if ($this->slm->getSession()) {
378 $max_idle = (int) ilSession::getIdleValue();
379 if ($session_timeout > $max_idle) {
380 $session_timeout = $max_idle;
381 }
382 $min_idle = (int) $ilSetting->get('session_min_idle', (string) ilSessionControl::DEFAULT_MIN_IDLE) * 60;
383 if ($session_timeout > $min_idle) {
384 $session_timeout = $min_idle;
385 }
386 $session_timeout -= 10; //buffer
387 } else {
388 $session_timeout = 0;
389 }
390 $config['session_ping'] = $session_timeout;
391
392 //url strings
393 $store_url = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=cmi&ref_id=' . $this->ref_id;
394 $unload_url = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=scormPlayerUnload&ref_id=' . $this->ref_id;
395 if ($this->slm->getSessionDeactivated()) {
396 $store_url = 'storeScorm2004.php?package_id=' . $this->packageId . '&ref_id=' . $this->ref_id . '&client_id=' . CLIENT_ID . '&do=store';
397 $unload_url = 'storeScorm2004.php?package_id=' . $this->packageId . '&ref_id=' . $this->ref_id . '&client_id=' . CLIENT_ID . '&do=unload';
398 }
399 $config['cp_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=cp&ref_id=' . $this->ref_id;
400 $config['cmi_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=cmi&ref_id=' . $this->ref_id;
401 $config['store_url'] = $store_url;
402 $config['get_adldata_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=getSharedData&ref_id=' . $this->ref_id;
403 $config['set_adldata_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=setSharedData&ref_id=' . $this->ref_id;
404 $config['adlact_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=adlact&ref_id=' . $this->ref_id;
405 $config['specialpage_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=specialPage&ref_id=' . $this->ref_id;
406 $config['suspend_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=suspend&ref_id=' . $this->ref_id;
407 $config['get_suspend_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=getSuspend&ref_id=' . $this->ref_id;
408 //next 2 lines could be deleted later
409 $config['gobjective_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=gobjective&ref_id=' . $this->ref_id;
410 $config['get_gobjective_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=getGobjective&ref_id=' . $this->ref_id;
411 $config['ping_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=pingSession&ref_id=' . $this->ref_id;
412 $config['scorm_player_unload_url'] = $unload_url;
413 $config['post_log_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=postLogEntry&ref_id=' . $this->ref_id;
414 $config['livelog_url'] = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=liveLogContent&ref_id=' . $this->ref_id;
415 $config['package_url'] = $this->getDataDirectory() . "/";
416
417 //editor
418 $config['envEditor'] = 0;
419
420 //debug
421 $config['debug'] = $this->slm->getDebug();
422 $config['debug_fields'] = $this->getDebugValues();
423 $config['debug_fields_test'] = $this->getDebugValues(true);
424
425 //language strings
426 $langstrings['btnStart'] = $lng->txt('scplayer_start');
427 $langstrings['btnExit'] = $lng->txt('scplayer_exit');
428 $langstrings['btnExitAll'] = $lng->txt('scplayer_exitall');
429 $langstrings['btnSuspendAll'] = $lng->txt('scplayer_suspendall');
430 $langstrings['btnPrevious'] = $lng->txt('scplayer_previous');
431 $langstrings['btnContinue'] = $lng->txt('scplayer_continue');
432 $langstrings['btnhidetree'] = $lng->txt('scplayer_hidetree');
433 $langstrings['btnshowtree'] = $lng->txt('scplayer_showtree');
434 $langstrings['linkexpandTree'] = $lng->txt('scplayer_expandtree');
435 $langstrings['linkcollapseTree'] = $lng->txt('scplayer_collapsetree');
436 $langstrings['contCreditOff'] = $lng->txt('cont_credit_off');
437 if ($this->slm->getAutoReviewChar() === "s") {
438 $langstrings['contCreditOff'] = $lng->txt('cont_sc_score_was_higher_message');
439 }
440 $config['langstrings'] = $langstrings;
441
442 //template variables
443 //$this->tpl = new ilTemplate("tpl.scorm2004.player.html", false, false, "Modules/Scorm2004");
444 $this->tpl = new ilGlobalTemplate("tpl.scorm2004.player.html", true, true, "Modules/Scorm2004");
445 $this->tpl->setVariable("JS_FILE", iljQueryUtil::getLocaljQueryPath());
446
447 // include ilias rte css, if given
448 $rte_css = $this->slm->getDataDirectory() . "/ilias_css_4_2/css/style.css";
449 if (is_file($rte_css)) {
450 $this->tpl->setCurrentBlock("rte_css");
451 $this->tpl->setVariable("RTE_CSS", $rte_css);
452 $this->tpl->parseCurrentBlock();
453 }
454
455
456 $this->tpl->setVariable('JSON_LANGSTRINGS', json_encode($langstrings));
457 // include_once("./Services/YUI/classes/class.ilYuiUtil.php");
458 // $this->tpl->setVariable('YUI_PATH', ilYuiUtil::getLocalPath());
459 // $this->tpl->setVariable('TREE_JS', "./Services/UIComponent/NestedList/js/ilNestedList.js");
460 $this->tpl->setVariable('TREE_JS', "./Modules/Scorm2004/scripts/ilNestedList.js");
461 foreach ($langstrings as $key => $value) {
462 $this->tpl->setVariable($key, $value);
463 }
464 $this->tpl->setVariable('DOC_TITLE', 'ILIAS: ' . $this->slm->getTitle());
465 $this->tpl->setVariable("LOCATION_FAVICON", ilUtil::getImagePath("favicon.ico", ""));
466 $this->tpl->setVariable("LOCATION_STYLESHEET", ilUtil::getStyleSheetLocation());
467 $this->tpl->setVariable('INIT_CP_DATA', json_encode(json_decode($this->getCPDataInit())));
468 $this->tpl->setVariable('INIT_CMI_DATA', json_encode($this->getCMIData($this->userId, $this->packageId)));
469 $this->tpl->setVariable('INIT_ADLACT_DATA', json_encode($initAdlactData));
470 $this->tpl->setVariable('INIT_GLOBALOBJ_DATA', json_encode($initGlobalobjData));
471 $this->tpl->setVariable('JS_DATA', json_encode($config));
472 list($tsfrac, $tsint) = explode(' ', microtime());
473 $this->tpl->setVariable('TIMESTAMP', sprintf('%d%03d', $tsint, 1000 * (float) $tsfrac));
474 $this->tpl->setVariable('BASE_DIR', './Modules/Scorm2004/');
475 $this->tpl->setVariable('TXT_COLLAPSE', $lng->txt('scplayer_collapsetree'));
476 if ($this->slm->getDebug()) {
477 $this->tpl->setVariable('TXT_DEBUGGER', $lng->txt('scplayer_debugger'));
478 $this->tpl->setVariable('DEBUG_URL', "PopupCenter('ilias.php?baseClass=ilSAHSPresentationGUI&cmd=debugGUI&ref_id=" . $this->ref_id . "','Debug',800,600);");
479 } else {
480 $this->tpl->setVariable('TXT_DEBUGGER', '');
481 $this->tpl->setVariable('DEBUG_URL', '');
482 }
483
484 //set icons path
485 $this->tpl->setVariable('INLINE_CSS', ilSCORM13PlayerGUI::getInlineCss());
486
487 //include scripts
488 if ($this->slm->getCacheDeactivated()) {
489 $this->tpl->setVariable('JS_SCRIPTS', 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=getRTEjs&ref_id=' . $this->ref_id);
490 } else {
491 $this->tpl->setVariable('JS_SCRIPTS', './Modules/Scorm2004/scripts/buildrte/rte-min.js');
492 }
493
494 //disable top menu
495 if ($this->slm->getNoMenu() === true) {
496 $this->tpl->setVariable("VAL_DISPLAY", "style=\"display:none;\"");
497 } else {
498 $this->tpl->setVariable("VAL_DISPLAY", "");
499 }
500
501
502 //check for max_attempts and raise error if max_attempts is exceeded
503 // if ($this->get_max_attempts() != 0) {
504 // if ($this->get_actual_attempts() >= $this->get_max_attempts()) {
505 // header('Content-Type: text/html; charset=utf-8');
506 // echo($lng->txt("cont_sc_max_attempt_exceed"));
507 // exit;
508 // }
509 // }
510
511 //count attempt
513 $this->resetSharedData();
514
515 $this->tpl->printToStdout("DEFAULT", false);
516 }
517
518 public static function getInlineCSS(): string
519 {
520 $is_tpl = new ilTemplate("tpl.scorm2004.inlinecss.html", true, true, "Modules/Scorm2004");
521 $is_tpl->setVariable('IC_ASSET', ilUtil::getImagePath("scorm/asset.svg", ""));
522 $is_tpl->setVariable('IC_COMPLETED', ilUtil::getImagePath("scorm/completed.svg", ""));
523 $is_tpl->setVariable('IC_NOTATTEMPTED', ilUtil::getImagePath("scorm/not_attempted.svg", ""));
524 $is_tpl->setVariable('IC_RUNNING', ilUtil::getImagePath("scorm/running.svg", ""));
525 $is_tpl->setVariable('IC_INCOMPLETE', ilUtil::getImagePath("scorm/incomplete.svg", ""));
526 $is_tpl->setVariable('IC_PASSED', ilUtil::getImagePath("scorm/passed.svg", ""));
527 $is_tpl->setVariable('IC_FAILED', ilUtil::getImagePath("scorm/failed.svg", ""));
528 $is_tpl->setVariable('IC_BROWSED', ilUtil::getImagePath("scorm/browsed.svg", ""));
529 return $is_tpl->get();
530 }
531
532 public function getCPData(): void
533 {
534 $jsdata = $this->getCPDataInit();
535 if ($this->jsMode) {
536 header('Content-Type: text/javascript; charset=UTF-8');
537 print($jsdata);
538 } else {
539 header('Content-Type: text/plain; charset=UTF-8');
540 $jsdata = json_decode($jsdata);
541 print_r($jsdata);
542 }
543 }
544
545 public function getCPDataInit(): string
546 {
547 global $DIC;
548 $ilDB = $DIC->database();
549
550 $res = $ilDB->queryF(
551 'SELECT jsdata FROM cp_package WHERE obj_id = %s',
552 array('integer'),
553 array($this->packageId)
554 );
555 $packageData = $ilDB->fetchAssoc($res);
556
557 $jsdata = $packageData['jsdata'];
558 if (!$jsdata) {
559 $jsdata = 'null';
560 }
561
562 return $jsdata;
563 }
564
565
566 public function getADLActDataInit(): string
567 {
568 global $DIC;
569 $ilDB = $DIC->database();
570
571 $res = $ilDB->queryF(
572 'SELECT activitytree FROM cp_package WHERE obj_id = %s',
573 array('integer'),
574 array($this->packageId)
575 );
576 $data = $ilDB->fetchAssoc($res);
577
578 $activitytree = $data['activitytree'];
579
580 if (!$activitytree) {
581 $activitytree = 'null';
582 }
583 return $activitytree;
584 }
585
586 public function getADLActData(): void
587 {
588 $activitytree = $this->getADLActDataInit();
589 if ($this->jsMode) {
590 header('Content-Type: text/javascript; charset=UTF-8');
591 print($activitytree);
592 } else {
593 header('Content-Type: text/plain; charset=UTF-8');
594 $activitytree = json_decode($activitytree);
595 print_r($activitytree);
596 }
597 }
598
599 public function pingSession(): void
600 {
601 ilWACSignedPath::signFolderOfStartFile($this->getDataDirectory() . '/imsmanifest.xml');
602 //do nothing except returning header
603 header('Content-Type: text/plain; charset=UTF-8');
604 print("");
605 }
606
607 public function getScope(): string
608 {
609 global $DIC;
610 $ilDB = $DIC->database();
611 $ilUser = $DIC->user();
612
613 $res = $ilDB->queryF(
614 'SELECT global_to_system FROM cp_package WHERE obj_id = %s',
615 array('integer'),
616 array($this->packageId)
617 );
618 $data = $ilDB->fetchAssoc($res);
619
620 $gystem = $data['global_to_system'];
621 if ($gystem == 1) {
622 $gsystem = 'null';
623 } else {
624 $gsystem = (string) $this->packageId;
625 }
626
627 return $gsystem;
628 }
629
630 public function getSuspendDataInit(): string
631 {
632 global $DIC;
633 $ilDB = $DIC->database();
634 $ilUser = $DIC->user();
635
636 $res = $ilDB->queryF(
637 'SELECT data FROM cp_suspend WHERE obj_id = %s AND user_id = %s',
638 array('integer', 'integer'),
639 array($this->packageId, $ilUser->getId())
640 );
641 $data = $ilDB->fetchAssoc($res);
642
643 //delete delivered suspend data
644 $ilDB->manipulateF(
645 'DELETE FROM cp_suspend WHERE obj_id = %s AND user_id = %s',
646 array('integer', 'integer'),
647 array($this->packageId, $ilUser->getId())
648 );
649 if (is_array($data)) {
650 return $data['data'];
651 }
652 return "";
653 }
654
655 public function getSuspendData(): void
656 {
657 $suspend_data = $this->getSuspendDataInit();
658 if ($this->jsMode) {
659 header('Content-Type: text/javascript; charset=UTF-8');
660 print($suspend_data);
661 } else {
662 header('Content-Type: text/plain; charset=UTF-8');
663 $suspend_data = json_decode($suspend_data);
664 print_r($suspend_data);
665 }
666 }
667
668 public function suspendADLActData(): void
669 {
670 global $DIC;
671 $ilDB = $DIC->database();
672 $ilUser = $DIC->user();
673
674 $res = $ilDB->queryF(
675 'SELECT * FROM cp_suspend WHERE obj_id = %s AND user_id = %s',
676 array('integer', 'integer'),
677 array($this->packageId, $ilUser->getId())
678 );
679
680 if (!$ilDB->numRows($res)) {
681 $ilDB->insert('cp_suspend', array(
682 'data' => array('clob', file_get_contents('php://input')),
683 'obj_id' => array('integer', $this->packageId),
684 'user_id' => array('integer', $ilUser->getId())
685 ));
686 } else {
687 $ilDB->update(
688 'cp_suspend',
689 array(
690 'data' => array('clob', file_get_contents('php://input'))
691 ),
692 array(
693 'obj_id' => array('integer', $this->packageId),
694 'user_id' => array('integer', $ilUser->getId())
695 )
696 );
697 }
698 }
699
700 public function readGObjectiveInit(): array
701 {
702 global $DIC;
703 $ilDB = $DIC->database();
704 $ilUser = $DIC->user();
705
706 //get json string
707 $g_data = [];
708
709 $global_to_system = 1;
710
711 $res = $ilDB->queryF(
712 'SELECT global_to_system FROM cp_package WHERE obj_id = %s',
713 array('integer'),
714 array($this->packageId)
715 );
716 while ($data = $ilDB->fetchAssoc($res)) {
717 $global_to_system = $data['global_to_system'];
718 }
719
720 $query = 'SELECT objective_id, scope_id, satisfied, measure, user_id,
721 score_min, score_max, score_raw, completion_status,
722 progress_measure '
723 . 'FROM cmi_gobjective, cp_node, cp_mapinfo '
724 . 'WHERE (cmi_gobjective.objective_id <> %s AND cmi_gobjective.status IS NULL '
725 . 'AND cp_node.slm_id = %s AND cp_node.nodename = %s '
726 . 'AND cp_node.cp_node_id = cp_mapinfo.cp_node_id '
727 . 'AND cmi_gobjective.objective_id = cp_mapinfo.targetobjectiveid) '
728 . 'GROUP BY objective_id, scope_id, satisfied, measure, user_id,
729 score_min, score_max, score_raw, completion_status,
730 progress_measure';
731 $res = $ilDB->queryF(
732 $query,
733 array('text', 'integer', 'text'),
734 array('-course_overall_status-', $this->packageId, 'mapInfo')
735 );
736 while ($row = $ilDB->fetchAssoc($res)) {
737 if (($global_to_system == 1 && $row['scope_id'] == 0) || ($global_to_system == 0 && $row['scope_id'] == $this->packageId)) {
738 $learner = $row['user_id'];
739 $objective_id = $row['objective_id'];
740 if ($row['scope_id'] == 0) {
741 $scope = "null";
742 } else {
743 $scope = $row['scope_id'];
744 }
745
746 if ($row['satisfied'] != null) {
747 $toset = $row['satisfied'];
748 $g_data["satisfied"][$objective_id][$learner][$scope] = $toset;
749 }
750
751 if ($row['measure'] != null) {
752 $toset = $row['measure'];
753 $g_data["measure"][$objective_id][$learner][$scope] = $toset;
754 }
755
756 if ($row['score_raw'] != null) {
757 $toset = $row['score_raw'];
758 $g_data["score_raw"][$objective_id][$learner][$scope] = $toset;
759 }
760
761 if ($row['score_min'] != null) {
762 $toset = $row['score_min'];
763 $g_data["score_min"][$objective_id][$learner][$scope] = $toset;
764 }
765
766 if ($row['score_max'] != null) {
767 $toset = $row['score_max'];
768 $g_data["score_max"][$objective_id][$learner][$scope] = $toset;
769 }
770
771 if ($row['progress_measure'] != null) {
772 $toset = $row['progress_measure'];
773 $g_data["progress_measure"][$objective_id][$learner][$scope] = $toset;
774 }
775
776 if ($row['completion_status'] != null) {
777 $toset = $row['completion_status'];
778 $g_data["completion_status"][$objective_id][$learner][$scope] = $toset;
779 }
780 }
781 }
782 return $g_data;
783 }
784
785 public function readGObjective(): void
786 {
787 $gobjective_data = json_encode($this->readGObjectiveInit());
788 if ($this->jsMode) {
789 header('Content-Type: text/javascript; charset=UTF-8');
790 print($gobjective_data);
791 } else {
792 header('Content-Type: text/plain; charset=UTF-8');
793 $gobjective_data = json_decode($gobjective_data);
794 print_r($gobjective_data);
795 }
796 }
797
798
799 //Read the shared datascores for a given SCO
800 public function readSharedData(int $sco_node_id): void
801 {
802 global $DIC;
803 $ilDB = $DIC->database();
804 $ilUser = $DIC->user();
805 $dataStores = array( "data" => array(),
806 "permissions" => array());
807 $readPermissions = array();
808
809 $query = 'SELECT target_id, read_shared_data, write_shared_data '
810 . 'FROM cp_datamap '
811 . 'WHERE slm_id = %s '
812 . 'AND sco_node_id = %s '
813 . 'GROUP BY target_id, read_shared_data, write_shared_data';
814
815
816 $res = $ilDB->queryF(
817 $query,
818 array('integer', 'integer'),
819 array($this->packageId, $sco_node_id)
820 );
821
822 //Pass 1: Get all the shared data target_ids
823 // for this content package
824 while ($row = $ilDB->fetchAssoc($res)) {
825 $storeVal = ($row['read_shared_data'] == 0 && $row['write_shared_data'] == 1)
826 ? 'notWritten'
827 : null;
828
829 $dataStores["data"][$row['target_id']] = array( "store" => $storeVal,
830 "readSharedData" => $row['read_shared_data'],
831 "writeSharedData" => $row['write_shared_data']);
832 $dataStores["readPermissions"][$row['target_id']] = $row['read_shared_data'];
833 }
834
835 if (count($dataStores) < 1) {
836 //If there are no datastores, then return nothing
837 echo "";
838 exit();
839 }
840
841 if ($dataStores["readPermissions"] != null && array_sum($dataStores["readPermissions"]) != 0) {
842
843 //If there exists at least one readSharedData permission, then
844 //fill in the existing values (if any) already in the store.
845
846 //Create the params to add to the Pass 2 query (get existing values)
847 $params = array("types" => array("integer", "integer"),
848 "values" => array($this->userId, $this->packageId));
849
850 $paramTemplate = '';
851
852 //See if readSharedData is set for each datamap.
853 //If set to true, then add it to the search query
854 foreach ($dataStores["data"] as $key => $val) {
855 if ($dataStores["readPermissions"][$key] == 1
856 && $dataStores["data"][$key]["store"] !== 'notWritten') {
857 $params["types"][] = "text";
858 $params["values"][] = $key;
859 $paramTemplate .= '%s, ';
860 }
861 }
862
863 //Get rid of the trailing ', '
864 $paramTemplate = substr($paramTemplate, 0, -2);
865
866 //Pass 2: Query for values previously saved by the user
867 $query = 'SELECT target_id, store '
868 . 'FROM adl_shared_data '
869 . 'WHERE user_id = %s '
870 . 'AND slm_id = %s '
871 . 'AND target_id IN (' . $paramTemplate . ')';
872
873
874 $res = $ilDB->queryF(
875 $query,
876 $params["types"],
877 $params["values"]
878 );
879
880 while ($row = $ilDB->fetchAssoc($res)) {
881 $dataStores["data"][$row['target_id']]["store"] = $row['store'];
882 }
883 }
884
885 header('Content-Type: text/javascript; charset=UTF-8');
886
887 echo json_encode($dataStores["data"]);
888 }
889
890 public function writeSharedData(int $sco_node_id): void
891 {
892 global $DIC;
893 $ilDB = $DIC->database();
894 $ilUser = $DIC->user();
895 $g_data = json_decode(file_get_contents('php://input'));
896
897 //Step 1: Get the writeable stores for this SCO that already have values
898 $query = 'SELECT dm.target_id, sd.store '
899 . 'FROM cp_datamap dm '
900 . 'LEFT JOIN adl_shared_data sd '
901 . 'ON(dm.slm_id = sd.slm_id AND dm.target_id = sd.target_id) '
902 . 'WHERE sco_node_id = %s '
903 . 'AND dm.slm_id = %s '
904 . 'AND write_shared_data = 1 '
905 . 'AND user_id = %s';
906
907 $res = $ilDB->QueryF(
908 $query,
909 array('integer', 'integer', 'integer'),
910 array($sco_node_id, $this->packageId, $this->userId)
911 );
912
913 $dataStores = array();
914 $originalVals = array();
915 while ($row = $ilDB->fetchAssoc($res)) {
916 $id = $row['target_id'];
917 $dataStores[$id] = $g_data->{$id};
918 $originalVals[$id] = $row['store'];
919 }
920
921
922 //Step 2: Add the writeable stores
923 foreach ($g_data as $key => $obj) {
924 //If it's already created in adl_shared_data, we
925 //need to update it.
926 if (array_key_exists($key, $dataStores)) {
927 if ($obj === 'notWritten') {
928 continue;
929 }
930
931 $query = 'UPDATE adl_shared_data '
932 . 'SET store = %s '
933 . 'WHERE user_id = %s '
934 . 'AND target_id = %s '
935 . 'AND slm_id = %s ';
936
937 $ilDB->manipulateF(
938 $query,
939 array('text', 'integer', 'text', 'integer'),
940 array($dataStores[$key], $this->userId, $key, $this->packageId)
941 );
942 } else {
943 //Check for writability
944 $res = $ilDB->queryF(
945 'SELECT write_shared_data, cp_node_id '
946 . 'FROM cp_datamap '
947 . 'WHERE target_id = %s '
948 . 'AND slm_id = %s '
949 . 'AND sco_node_id = %s',
950 array('text', 'integer', 'integer'),
951 array($key, $this->packageId, $sco_node_id)
952 );
953
954 $row = $ilDB->fetchAssoc($res);
955 if ($row["write_shared_data"] != 1) {
956 continue;
957 }
958
959 //If it's writeable, then add the new value into the database
960 $res = $ilDB->manipulateF(
961 'INSERT INTO adl_shared_data (slm_id, user_id, target_id, store, cp_node_id) VALUES (%s, %s, %s, %s, %s)',
962 array('integer', 'integer', 'text', 'text', 'integer'),
963 array($this->packageId, $this->userId, $key, $obj, $row["cp_node_id"])
964 );
965 }
966 }
967 echo "1";
968 exit;
969 }
970
971 public function specialPage(): void
972 {
973 global $DIC;
974 $lng = $DIC->language();
975
976 $specialpages = array(
977 "_COURSECOMPLETE_" => "seq_coursecomplete",
978 "_ENDSESSION_" => "seq_endsession",
979 "_SEQBLOCKED_" => "seq_blocked",
980 "_NOTHING_" => "seq_nothing",
981 "_ERROR_" => "seq_error",
982 "_DEADLOCK_" => "seq_deadlock",
983 "_INVALIDNAVREQ_" => "seq_invalidnavreq",
984 "_SEQABANDON_" => "seq_abandon",
985 "_SEQABANDONALL_" => "seq_abandonall",
986 "_TOC_" => "seq_toc",
987 "" => ""
988 );
989
990 $this->tpl = new ilGlobalTemplate("tpl.scorm2004.specialpages.html", false, false, "Modules/Scorm2004");
991 $this->tpl->setVariable("LOCATION_STYLESHEET", ilUtil::getStyleSheetLocation());
992 $this->tpl->setVariable('TXT_SPECIALPAGE', $lng->txt($specialpages[$this->page]));
993 if ($this->page !== "_TOC_" && $this->page !== "_SEQABANDON_" && $this->page !== "_SEQABANDONALL_") {
994 $this->tpl->setVariable('CLOSE_WINDOW', $lng->txt('seq_close'));
995 } else {
996 $this->tpl->setVariable('CLOSE_WINDOW', "");
997 }
998 $this->tpl->printToStdout("DEFAULT", false);
999 }
1000
1001
1002 public function fetchCMIData(): void
1003 {
1004 $data = $this->getCMIData($this->userId, $this->packageId);
1005 if ($this->jsMode) {
1006 header('Content-Type: text/javascript; charset=UTF-8');
1007 print(json_encode($data));
1008 } else {
1009 header('Content-Type: text/plain; charset=UTF-8');
1010 print(var_export($data, true));
1011 }
1012 }
1013
1014
1015 // /**
1016 // * maps API data structure type to internal datatype on a node
1017 // * and accepts only valid values, dropping invalid ones from input
1018 // */
1019 // private function normalizeFields($table, &$node) : void
1020 // {
1021 // return;
1022 // foreach (self::$schema[$table] as $k => $v) {
1023 // $value = $node->$k;
1024 // if (isset($value) && is_string($v) && !preg_match($v, $value)) {
1025 // unset($node->$k);
1026 // }
1027 // }
1028 // }
1029
1033 public function getCMIData(int $userId, int $packageId): array
1034 {
1035 global $DIC;
1036 $ilDB = $DIC->database();
1037
1038 $i_check = 0;
1039 $result = array(
1040 'schema' => array(),
1041 'data' => array()
1042 );
1043
1044 foreach (self::$schema as $k => &$v) {
1045 $result['schema'][$k] = array_keys($v);
1046 $q = '';
1047 switch ($k) {
1048 case "node":
1049 $q = 'SELECT cmi_node.*
1050 FROM cmi_node
1051 INNER JOIN cp_node ON cmi_node.cp_node_id = cp_node.cp_node_id
1052 WHERE cmi_node.user_id = %s
1053 AND cp_node.slm_id = %s';
1054
1055 break;
1056
1057 case "comment":
1058 if ($i_check > 7) {
1059 $i_check -= 8;
1060 if ($this->slm->getComments()) {
1061 $q = 'SELECT
1062 cmi_comment.cmi_comment_id,
1063 cmi_comment.cmi_node_id,
1064 cmi_comment.c_comment,
1065 cmi_comment.c_timestamp,
1066 cmi_comment.location,
1067 cmi_comment.sourceislms
1068 FROM cmi_comment
1069 INNER JOIN cmi_node ON cmi_node.cmi_node_id = cmi_comment.cmi_node_id
1070 INNER JOIN cp_node ON cp_node.cp_node_id = cmi_node.cp_node_id
1071 WHERE cmi_node.user_id = %s
1072 AND cp_node.slm_id = %s
1073 ORDER BY cmi_comment.cmi_comment_id';
1074 }
1075 }
1076
1077 break;
1078
1079 case "correct_response":
1080 if ($i_check > 3) {
1081 $i_check -= 4;
1082 if ($this->slm->getInteractions()) {
1083 $q = 'SELECT cmi_correct_response.*
1084 FROM cmi_correct_response
1085 INNER JOIN cmi_interaction
1086 ON cmi_interaction.cmi_interaction_id = cmi_correct_response.cmi_interaction_id
1087 INNER JOIN cmi_node ON cmi_node.cmi_node_id = cmi_interaction.cmi_node_id
1088 INNER JOIN cp_node ON cp_node.cp_node_id = cmi_node.cp_node_id
1089 WHERE cmi_node.user_id = %s
1090 AND cp_node.slm_id = %s
1091 ORDER BY cmi_correct_response.cmi_correct_resp_id';
1092 }
1093 }
1094 break;
1095
1096 case "interaction":
1097 if ($i_check > 1) {
1098 $i_check -= 2;
1099 if ($this->slm->getInteractions()) {
1100 $q = 'SELECT
1101 cmi_interaction.cmi_interaction_id,
1102 cmi_interaction.cmi_node_id,
1103 cmi_interaction.description,
1104 cmi_interaction.id,
1105 cmi_interaction.latency,
1106 cmi_interaction.learner_response,
1107 cmi_interaction.result,
1108 cmi_interaction.c_timestamp,
1109 cmi_interaction.c_type,
1110 cmi_interaction.weighting
1111 FROM cmi_interaction
1112 INNER JOIN cmi_node ON cmi_node.cmi_node_id = cmi_interaction.cmi_node_id
1113 INNER JOIN cp_node ON cp_node.cp_node_id = cmi_node.cp_node_id
1114 WHERE cmi_node.user_id = %s
1115 AND cp_node.slm_id = %s
1116 ORDER BY cmi_interaction.cmi_interaction_id';
1117 }
1118 }
1119 break;
1120
1121 case "objective":
1122 if ($i_check > 0) {
1123 if ($this->slm->getObjectives()) {
1124 $q = 'SELECT
1125 cmi_objective.cmi_interaction_id,
1126 cmi_objective.cmi_node_id,
1127 cmi_objective.cmi_objective_id,
1128 cmi_objective.completion_status,
1129 cmi_objective.description,
1130 cmi_objective.id,
1131 cmi_objective.c_max,
1132 cmi_objective.c_min,
1133 cmi_objective.c_raw,
1134 cmi_objective.scaled,
1135 cmi_objective.progress_measure,
1136 cmi_objective.success_status,
1137 cmi_objective.scope
1138 FROM cmi_objective
1139 INNER JOIN cmi_node ON cmi_node.cmi_node_id = cmi_objective.cmi_node_id
1140 INNER JOIN cp_node ON cp_node.cp_node_id = cmi_node.cp_node_id
1141 WHERE cmi_node.user_id = %s
1142 AND cp_node.slm_id = %s
1143 ORDER BY cmi_objective.cmi_objective_id';
1144 }
1145 }
1146 break;
1147
1148 case "package"://delete because data exist except of learner_name
1149 $q = 'SELECT usr_data.usr_id user_id,
1150 CONCAT(CONCAT(COALESCE(usr_data.firstname, \'\'), \' \'), COALESCE(usr_data.lastname, \'\')) learner_name,
1151 sahs_lm.id slm_id , sahs_lm.default_lesson_mode "mode", sahs_lm.credit
1152 FROM usr_data, cp_package
1153 INNER JOIN sahs_lm ON cp_package.obj_id = sahs_lm.id
1154 WHERE usr_data.usr_id = %s
1155 AND sahs_lm.id = %s';
1156
1157 break;
1158
1159 }
1160
1161 $result['data'][$k] = array();
1162 if ($q != '') {
1163 $types = array('integer', 'integer');
1164 $values = array($userId, $packageId);
1165 $res = $ilDB->queryF($q, $types, $values);
1166
1167 while ($row = $ilDB->fetchAssoc($res)) {
1168 $tmp_result = array();
1169 foreach ($row as $key => $value) {
1170 if ($k === "comment" && $key === "c_timestamp" && strpos($value, ' ') == 10) {
1171 $value = str_replace(' ', 'T', $value);
1172 }
1173 $tmp_result[] = $value;
1174 if ($k === "node" && $key === "additional_tables" && $i_check < $value) {
1175 $i_check = $value;
1176 // $GLOBALS['DIC']['ilLog']->write($i_check);
1177 }
1178 }
1179 $result['data'][$k][] = $tmp_result;
1180 }
1181 }
1182 }
1183 return $result;
1184 }
1185
1189 public function quoteJSONArray(?array $a_array): array
1190 {
1191 global $DIC;
1192 $ilDB = $DIC->database();
1193
1194 if (!is_array($a_array) or !count($a_array)) {
1195 return array("''");
1196 }
1197
1198 foreach ($a_array as $k => $item) {
1199 if ($item != null) {
1200 $a_array[$k] = $ilDB->quote($item);
1201 } else {
1202 $a_array[$k] = "NULL";
1203 }
1204 }
1205
1206 return $a_array;
1207 }
1208
1209 // /**
1210 // * estimate content type for a filename by extension
1211 // * first do it for common static web files from external list
1212 // * if not found peek into file by slow php function mime_content_type()
1213 // * @param $filename required
1214 // * @return string mimetype name e.g. image/jpeg
1215 // */
1216 // public function getMimetype($filename)
1217 // {
1218 // include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1219 // return ilObjMediaObject::getMimeType($filename);
1220 // }
1221
1222
1223 // /**
1224 // * Get max. number of attempts allowed for this package
1225 // */
1226 // public function get_max_attempts()
1227 // {
1228 // include_once "./Modules/ScormAicc/classes/SCORM/class.ilObjSCORMInitData.php";
1229 // return ilObjSCORMInitData::get_max_attempts($this->packageId);
1230 // }
1231
1232 public function get_Module_Version(): int
1233 {
1234 global $DIC;
1235 $ilDB = $DIC->database();
1236
1237 $res = $ilDB->queryF(
1238 'SELECT module_version FROM sahs_lm WHERE id = %s',
1239 array('integer'),
1240 array($this->packageId)
1241 );
1242 $row = $ilDB->fetchAssoc($res);
1243
1244 return (int) $row['module_version'];
1245 }
1246
1250 public function get_actual_attempts(): int
1251 {
1252 global $DIC;
1253 $ilDB = $DIC->database();
1254 $ilUser = $DIC->user();
1255 $val_set = $ilDB->queryF(
1256 'SELECT package_attempts FROM sahs_user WHERE obj_id = %s AND user_id = %s',
1257 array('integer','integer'),
1258 array($this->packageId,$this->userId)
1259 );
1260 $val_rec = $ilDB->fetchAssoc($val_set);
1261 $attempts = $val_rec["package_attempts"];
1262 if ($attempts == null) {
1263 $attempts = 0;
1264 }
1265 return (int) $attempts;
1266 }
1267
1272 {
1273 global $DIC;
1274 $ilDB = $DIC->database();
1275 $ilUser = $DIC->user();
1276 $res = $ilDB->queryF(
1277 'SELECT package_attempts,count(*) cnt FROM sahs_user WHERE obj_id = %s AND user_id = %s GROUP BY package_attempts',
1278 array('integer','integer'),
1279 array($this->slm->getId(),$ilUser->getId())
1280 );
1281 $val_rec = $ilDB->fetchAssoc($res);
1282 if ($val_rec["cnt"] == 0) { //offline_mode could be inserted
1283 $attempts = 1;
1284 $ilDB->manipulateF(
1285 'INSERT INTO sahs_user (obj_id,user_id,package_attempts,module_version,last_access) VALUES(%s,%s,%s,%s,%s)',
1286 array('integer', 'integer', 'integer', 'integer', 'timestamp'),
1287 array($this->slm->getId(), $ilUser->getId(), $attempts, $this->slm->getModuleVersion(), date('Y-m-d H:i:s'))
1288 );
1289 } else {
1290 $attempts = $val_rec["package_attempts"];
1291 if ($attempts == null) {
1292 $attempts = 0;
1293 }
1294 $attempts++;
1295 $ilDB->manipulateF(
1296 'UPDATE sahs_user SET package_attempts = %s, module_version = %s, last_access=%s WHERE obj_id = %s AND user_id = %s ',
1297 array('integer', 'integer', 'timestamp', 'integer', 'integer'),
1298 array($attempts, $this->slm->getModuleVersion(), date('Y-m-d H:i:s'), $this->slm->getId(), $ilUser->getId())
1299 );
1300 }
1301 }
1302
1303 public function resetSharedData(): void
1304 {
1305 global $DIC;
1306 $ilDB = $DIC->database();
1307 //Reset the shared data stores if sharedDataGlobalToSystem is false
1308 $res = $ilDB->queryF(
1309 'SELECT shared_data_global_to_system FROM cp_package WHERE obj_id = %s',
1310 array('integer'),
1311 array($this->packageId)
1312 );
1313
1314 $shared_global_to_sys = $ilDB->fetchObject($res)->shared_data_global_to_system;
1315
1316 $res = $ilDB->queryF(
1317 'SELECT data FROM cp_suspend WHERE obj_id = %s AND user_id = %s',
1318 array('integer', 'integer'),
1319 array($this->packageId, $this->userId)
1320 );
1321
1322 $suspended = false;
1323 while ($data = $ilDB->fetchAssoc($res)) {
1324 $dat = $data['data'];
1325 if ($dat != null && $dat != '') {
1326 $suspended = true;
1327 }
1328 }
1329
1330 if ($shared_global_to_sys == 0 && !$suspended) {
1331 $ilDB->manipulateF(
1332 'DELETE FROM adl_shared_data WHERE slm_id = %s AND user_id = %s',
1333 array('integer', 'integer'),
1334 array($this->packageId, $this->userId)
1335 );
1336 }
1337 }
1338
1339 //debug extentions
1343 private function getNodeData(string $sco_id): array
1344 {
1345 global $DIC;
1346 $ilDB = $DIC->database();
1347 $ilLog = ilLoggerFactory::getLogger('sc13');
1348
1349 $fieldList = "cmi_node.cp_node_id, cmi_node.completion_threshold, cmi_node.c_exit, cmi_node.completion_status, cmi_node.progress_measure, cmi_node.success_status, cmi_node.scaled, cmi_node.session_time," .
1350 "cmi_node.c_min, cmi_node.c_max, cmi_node.c_raw, cmi_node.location, cmi_node.suspend_data, cmi_node.scaled_passing_score, cmi_node.total_time";
1351
1352
1353 $res = $ilDB->queryF(
1354 '
1355 SELECT ' . $fieldList . '
1356 FROM cmi_node,cp_node,cp_item
1357 WHERE cp_node.slm_id = %s
1358 AND cp_node.cp_node_id = cp_item.cp_node_id
1359 AND cp_item.id = %s
1360 AND cmi_node.cp_node_id = cp_item.cp_node_id
1361 AND cmi_node.user_id = %s',
1362 array('integer','text','integer'),
1363 array($this->packageId, $sco_id, $this->userId)
1364 );
1365 // $ilLog->write("DEBUG SQL" . $row);
1366 return $ilDB->fetchAssoc($res);
1367 }
1368
1369 private function logTmpName(): string
1370 {
1371 $filename = $this->logDirectory() . "/" . $this->packageId . ".tmp";
1372 if (!file_exists($filename)) {
1373 umask(0000);
1374 $fHandle = fopen($filename, 'a') or die("can't open file");
1375 fwrite($fHandle, "");
1376 fclose($fHandle);
1377 }
1378 return $filename;
1379 }
1380
1381 private function summaryFileName(): string
1382 {
1383 $filename = $this->logDirectory() . "/" . $this->packageId . "_summary_" . $this->get_actual_attempts();
1384 $adder = "0";
1385 $suffix = ".csv";
1386 $i = 0;
1387 while (file_exists($filename . "_" . $adder . $suffix)) {
1388 $i++;
1389 $adder = (string) $i;
1390 }
1391 $retname = $filename . "_" . $adder . $suffix;
1392
1393 if (!file_exists($retname)) {
1394 umask(0000);
1395 $fHandle = fopen($retname, 'a') or die("can't open file");
1396 fwrite($fHandle, "");
1397 fclose($fHandle);
1398 }
1399 return $retname;
1400 }
1401
1402 private function logFileName(): string
1403 {
1404 global $DIC;
1405 $lng = $DIC->language();
1406 $lng->loadLanguageModule("scormdebug");
1407
1408 $filename = $this->logDirectory() . "/" . $this->packageId . "_" . $this->get_actual_attempts();
1409 $path_csv = $filename . ".csv";
1410 $path_txt = $filename . ".html";
1411 if (!file_exists($path_csv)) {
1412 umask(0000);
1413 $fHandle = fopen($path_csv, 'a') or die("can't open file");
1414 $string = '"CourseId";"ScoId";"ScoTitle";"Timestamp";"Action";"Key";"Value";"Return Value";"Errorcode";"Timespan";"ErrorDescription"' . "\n";
1415 fwrite($fHandle, $string);
1416 fclose($fHandle);
1417 }
1418 if (!file_exists($path_txt)) {
1419 if (file_exists($this->logTmpName())) {
1420 unlink($this->logTmpName());
1421 }
1422 umask(0000);
1423 $fHandle2 = fopen($path_txt, 'a') or die("can't open file");
1424 $logtpl = $this->getLogTemplate();
1425 $logtpl->setCurrentBlock('NewLog');
1426 $logtpl->setVariable("COURSETITLE", $this->slm->getTitle());
1427 $logtpl->setVariable("COURSEID", $this->packageId);
1428 $logtpl->setVariable("TIMESTAMP", date("d.m.Y H:i", time()));
1429 $logtpl->setVariable("SESSION", $this->get_actual_attempts());
1430 $logtpl->setVariable("error0", $lng->txt("error0"));
1431 $logtpl->setVariable("error101", $lng->txt("error101"));
1432 $logtpl->setVariable("error102", $lng->txt("error102"));
1433 $logtpl->setVariable("error103", $lng->txt("error103"));
1434 $logtpl->setVariable("error104", $lng->txt("error104"));
1435 $logtpl->setVariable("error111", $lng->txt("error111"));
1436 $logtpl->setVariable("error112", $lng->txt("error112"));
1437 $logtpl->setVariable("error113", $lng->txt("error113"));
1438 $logtpl->setVariable("error122", $lng->txt("error122"));
1439 $logtpl->setVariable("error123", $lng->txt("error123"));
1440 $logtpl->setVariable("error132", $lng->txt("error132"));
1441 $logtpl->setVariable("error133", $lng->txt("error133"));
1442 $logtpl->setVariable("error142", $lng->txt("error142"));
1443 $logtpl->setVariable("error143", $lng->txt("error143"));
1444 $logtpl->setVariable("error201", $lng->txt("error201"));
1445 $logtpl->setVariable("error301", $lng->txt("error301"));
1446 $logtpl->setVariable("error351", $lng->txt("error351"));
1447 $logtpl->setVariable("error391", $lng->txt("error391"));
1448 $logtpl->setVariable("error401", $lng->txt("error401"));
1449 $logtpl->setVariable("error402", $lng->txt("error402"));
1450 $logtpl->setVariable("error403", $lng->txt("error403"));
1451 $logtpl->setVariable("error404", $lng->txt("error404"));
1452 $logtpl->setVariable("error405", $lng->txt("error405"));
1453 $logtpl->setVariable("error406", $lng->txt("error406"));
1454 $logtpl->setVariable("error407", $lng->txt("error407"));
1455 $logtpl->setVariable("error408", $lng->txt("error408"));
1456 $logtpl->setVariable("SetValue", $lng->txt("SetValue"));
1457 $logtpl->setVariable("GetValue", $lng->txt("GetValue"));
1458 $logtpl->setVariable("Commit", $lng->txt("Commit"));
1459 $logtpl->setVariable("Initialize", $lng->txt("Initialize"));
1460 $logtpl->setVariable("Terminate", $lng->txt("Terminate"));
1461 $logtpl->setVariable("GetErrorString", $lng->txt("GetErrorString"));
1462 $logtpl->setVariable("GetLastError", $lng->txt("GetLastError"));
1463 $logtpl->setVariable("GetDiagnostic", $lng->txt("GetDiagnostic"));
1464 $logtpl->setVariable("cmi._version", $lng->txt("cmi._version"));
1465 $logtpl->setVariable("cmi.comments_from_learner._children", $lng->txt("cmi.comments_from_learner._children"));
1466 $logtpl->setVariable("cmi.comments_from_learner._count", $lng->txt("cmi.comments_from_learner._count"));
1467 $logtpl->setVariable("cmi.comments_from_learner.n.comment", $lng->txt("cmi.comments_from_learner.n.comment"));
1468 $logtpl->setVariable("cmi.comments_from_learner.n.location", $lng->txt("cmi.comments_from_learner.n.location"));
1469 $logtpl->setVariable("cmi.comments_from_learner.n.timestamp", $lng->txt("cmi.comments_from_learner.n.timestamp"));
1470 $logtpl->setVariable("cmi.comments_from_lms._children", $lng->txt("cmi.comments_from_lms._children"));
1471 $logtpl->setVariable("cmi.comments_from_lms._count", $lng->txt("cmi.comments_from_lms._count"));
1472 $logtpl->setVariable("cmi.comments_from_lms.n.comment", $lng->txt("cmi.comments_from_lms.n.comment"));
1473 $logtpl->setVariable("cmi.comments_from_lms.n.location", $lng->txt("cmi.comments_from_lms.n.location"));
1474 $logtpl->setVariable("cmi.comments_from_lms.n.timestamp", $lng->txt("cmi.comments_from_lms.n.timestamp"));
1475 $logtpl->setVariable("cmi.completion_status", $lng->txt("cmi.completion_status"));
1476 $logtpl->setVariable("cmi.completion_threshold", $lng->txt("cmi.completion_threshold"));
1477 $logtpl->setVariable("cmi.credit", $lng->txt("cmi.credit"));
1478 $logtpl->setVariable("cmi.entry", $lng->txt("cmi.entry"));
1479 $logtpl->setVariable("cmi.exit", $lng->txt("cmi.exit"));
1480 $logtpl->setVariable("cmi.interactions._children", $lng->txt("cmi.interactions._children"));
1481 $logtpl->setVariable("cmi.interactions._count", $lng->txt("cmi.interactions._count"));
1482 $logtpl->setVariable("cmi.interactions.n.id", $lng->txt("cmi.interactions.n.id"));
1483 $logtpl->setVariable("cmi.interactions.n.type", $lng->txt("cmi.interactions.n.type"));
1484 $logtpl->setVariable("cmi.interactions.n.objectives._count", $lng->txt("cmi.interactions.n.objectives._count"));
1485 $logtpl->setVariable("cmi.interactions.n.objectives.n.id", $lng->txt("cmi.interactions.n.objectives.n.id"));
1486 $logtpl->setVariable("cmi.interactions.n.timestamp", $lng->txt("cmi.interactions.n.timestamp"));
1487 $logtpl->setVariable("cmi.interactions.n.correct_responses._count", $lng->txt("cmi.interactions.n.correct_responses._count"));
1488 $logtpl->setVariable("cmi.interactions.n.correct_responses.n.pattern", $lng->txt("cmi.interactions.n.correct_responses.n.pattern"));
1489 $logtpl->setVariable("cmi.interactions.n.weighting", $lng->txt("cmi.interactions.n.weighting"));
1490 $logtpl->setVariable("cmi.interactions.n.learner_response", $lng->txt("cmi.interactions.n.learner_response"));
1491 $logtpl->setVariable("cmi.interactions.n.result", $lng->txt("cmi.interactions.n.result"));
1492 $logtpl->setVariable("cmi.interactions.n.latency", $lng->txt("cmi.interactions.n.latency"));
1493 $logtpl->setVariable("cmi.interactions.n.description", $lng->txt("cmi.interactions.n.description"));
1494 $logtpl->setVariable("cmi.launch_data", $lng->txt("cmi.launch_data"));
1495 $logtpl->setVariable("cmi.learner_id", $lng->txt("cmi.learner_id"));
1496 $logtpl->setVariable("cmi.learner_name", $lng->txt("cmi.learner_name"));
1497 $logtpl->setVariable("cmi.learner_preference._children", $lng->txt("cmi.learner_preference._children"));
1498 $logtpl->setVariable("cmi.learner_preference.audio_level", $lng->txt("cmi.learner_preference.audio_level"));
1499 $logtpl->setVariable("cmi.learner_preference.language", $lng->txt("cmi.learner_preference.language"));
1500 $logtpl->setVariable("cmi.learner_preference.delivery_speed", $lng->txt("cmi.learner_preference.delivery_speed"));
1501 $logtpl->setVariable("cmi.learner_preference.audio_captioning", $lng->txt("cmi.learner_preference.audio_captioning"));
1502 $logtpl->setVariable("cmi.location", $lng->txt("cmi.location"));
1503 $logtpl->setVariable("cmi.max_time_allowed", $lng->txt("cmi.max_time_allowed"));
1504 $logtpl->setVariable("cmi.mode", $lng->txt("cmi.mode"));
1505 $logtpl->setVariable("cmi.objectives._children", $lng->txt("cmi.objectives._children"));
1506 $logtpl->setVariable("cmi.objectives._count", $lng->txt("cmi.objectives._count"));
1507 $logtpl->setVariable("cmi.objectives.n.id", $lng->txt("cmi.objectives.n.id"));
1508 $logtpl->setVariable("cmi.objectives.n.score._children", $lng->txt("cmi.objectives.n.score._children"));
1509 $logtpl->setVariable("cmi.objectives.n.score.scaled", $lng->txt("cmi.objectives.n.score.scaled"));
1510 $logtpl->setVariable("cmi.objectives.n.score.raw", $lng->txt("cmi.objectives.n.score.raw"));
1511 $logtpl->setVariable("cmi.objectives.n.score.min", $lng->txt("cmi.objectives.n.score.min"));
1512 $logtpl->setVariable("cmi.objectives.n.score.max", $lng->txt("cmi.objectives.n.score.max"));
1513 $logtpl->setVariable("cmi.objectives.n.success_status", $lng->txt("cmi.objectives.n.success_status"));
1514 $logtpl->setVariable("cmi.objectives.n.completion_status", $lng->txt("cmi.objectives.n.completion_status"));
1515 $logtpl->setVariable("cmi.objectives.n.progress_measure", $lng->txt("cmi.objectives.n.progress_measure"));
1516 $logtpl->setVariable("cmi.objectives.n.description", $lng->txt("cmi.objectives.n.description"));
1517 $logtpl->setVariable("cmi.progress_measure", $lng->txt("cmi.progress_measure"));
1518 $logtpl->setVariable("cmi.scaled_passing_score", $lng->txt("cmi.scaled_passing_score"));
1519 $logtpl->setVariable("cmi.score._children", $lng->txt("cmi.score._children"));
1520 $logtpl->setVariable("cmi.score.scaled", $lng->txt("cmi.score.scaled"));
1521 $logtpl->setVariable("cmi.score.raw", $lng->txt("cmi.score.raw"));
1522 $logtpl->setVariable("cmi.score.min", $lng->txt("cmi.score.min"));
1523 $logtpl->setVariable("cmi.score.max", $lng->txt("cmi.score.max"));
1524 $logtpl->setVariable("cmi.session_time", $lng->txt("cmi.session_time"));
1525 $logtpl->setVariable("cmi.success_status", $lng->txt("cmi.success_status"));
1526 $logtpl->setVariable("cmi.suspend_data", $lng->txt("cmi.suspend_data"));
1527 $logtpl->setVariable("cmi.time_limit_action", $lng->txt("cmi.time_limit_action"));
1528 $logtpl->setVariable("cmi.total_time", $lng->txt("cmi.total_time"));
1529 $logtpl->setVariable("adl.nav.request", $lng->txt("adl.nav.request"));
1530 $logtpl->setVariable("adl.nav.request_valid.continue", $lng->txt("adl.nav.request_valid.continue"));
1531 $logtpl->setVariable("adl.nav.request_valid.previous", $lng->txt("adl.nav.request_valid.previous"));
1532 $logtpl->setVariable("adl.nav.request_valid.choice", $lng->txt("adl.nav.request_valid.choice"));
1533 $logtpl->setVariable("i_green", $lng->txt("i_green"));
1534 $logtpl->setVariable("i_red", $lng->txt("i_red"));
1535 $logtpl->setVariable("i_orange", $lng->txt("i_orange"));
1536 $logtpl->setVariable("i_fuchsia", $lng->txt("i_fuchsia"));
1537 $logtpl->setVariable("i_gray", $lng->txt("i_gray"));
1538 $logtpl->setVariable("error", $lng->txt("error"));
1539 $logtpl->setVariable("strange_error", $lng->txt("strange_error"));
1540 $logtpl->setVariable("strange_API-Call", $lng->txt("strange_API-Call"));
1541 $logtpl->setVariable("unknown", $lng->txt("unknown"));
1542 $logtpl->setVariable("undefined_color", $lng->txt("undefined_color"));
1543 $logtpl->setVariable("description_for", $lng->txt("description_for"));
1544 $logtpl->setVariable("hide", $lng->txt("hide"));
1545 $logtpl->setVariable("all_API-calls_shown", $lng->txt("all_API-calls_shown"));
1546 $logtpl->setVariable("show_only_important_API-calls", $lng->txt("show_only_important_API-calls"));
1547 $logtpl->setVariable("only_important_API-Calls_shown", $lng->txt("only_important_API-Calls_shown"));
1548 $logtpl->setVariable("show_all_API-calls", $lng->txt("show_all_API-calls"));
1549 $logtpl->setVariable("log_for", $lng->txt("log_for"));
1550 $logtpl->setVariable("started", $lng->txt("started"));
1551 $logtpl->setVariable("nr_session", $lng->txt("nr_session"));
1552 $logtpl->setVariable("id_learning_module", $lng->txt("id_learning_module"));
1553 if ($this->slm->getCheck_values() == false) {
1554 $logtpl->setVariable("CHECK_VALUES", $lng->txt("sent_values_not_checked"));
1555 }
1556 $logtpl->parseCurrentBlock();
1557 fwrite($fHandle2, $logtpl->get());
1558 fclose($fHandle2);
1559 }
1560 return $filename;
1561 }
1562
1563 public function getDataDirectory2(): string
1564 {
1565 $webdir = str_replace("/ilias.php", "", $_SERVER["SCRIPT_NAME"]);
1566 //load ressources always with absolute URL..relative URLS fail on innersco navigation on certain browsers
1567 $lm_dir = $webdir . "/" . ILIAS_WEB_DIR . "/" . CLIENT_ID . "/lm_data" . "/lm_" . $this->packageId;
1568 return $lm_dir;
1569 }
1570
1571 private function logDirectory(): string
1572 {
1573 // $logDir=ilUtil::getDataDir()."/SCORMlogs"."/lm_".$this->packageId;
1574 // if (!file_exists($logDir)) ilUtil::makeDirParents($logDir);
1575 $logDir = $this->slm->getDataDirectory() . "/logs";
1576 if (!file_exists($logDir)) {
1577 ilFileUtils::makeDir($logDir);
1578 }
1579 return $logDir;
1580 }
1581
1582 public function openLog(): void
1583 {
1584 global $DIC;
1585 $filename = ilUtil::stripSlashes($DIC->http()->wrapper()->query()->retrieve('logFile', $DIC->refinery()->kindlyTo()->string()));
1586 $filename = str_replace('/', '', $filename);
1587 //Header
1588 header('Content-Type: text/html; charset=UTF-8');
1589 echo file_get_contents($this->logDirectory() . "/" . $filename);
1590 exit;
1591 }
1592
1593 public function downloadLog(): void
1594 {
1595 global $DIC;
1596 $filename = ilUtil::stripSlashes($DIC->http()->wrapper()->query()->retrieve('logFile', $DIC->refinery()->kindlyTo()->string()));
1597 $filename = str_replace('/', '', $filename);
1598 //Header
1599 header("Expires: 0");
1600 header("Cache-Control: private");
1601 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
1602 header("Pragma: cache");
1603 header("Content-Description: File Transfer");
1604 header("Content-Type: application/octet-stream");
1605 header("Content-disposition: attachment; filename=$filename");
1606 echo file_get_contents($this->logDirectory() . "/" . $filename);
1607 exit;
1608 }
1609
1613 private function getLogFileList(string $s_delete, string $s_download, string $s_open): array
1614 {
1615 $data = array();
1616 foreach (new DirectoryIterator($this->logDirectory()) as $fileInfo) {
1617 if ($fileInfo->isDot()) {
1618 continue;
1619 }
1620 $item['filename'] = $fileInfo->getFilename();
1621 $parts = pathinfo($item['filename']);
1622 $fnameparts = preg_split('/_/', $parts['filename'], -1, PREG_SPLIT_NO_EMPTY);
1623 $deleteUrl = '&nbsp;<a href=#' . " onclick=\"javascript:deleteFile('" . $item['filename'] . "');\">" . $s_delete . "</a>";
1624 //no delete for most recent file
1625 if (isset($fnameparts[1]) && (string) $this->get_actual_attempts() == $fnameparts[1]) {
1626 $deleteUrl = "";
1627 }
1628
1629 $urlDownload = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=downloadLog&ref_id=' . $this->ref_id . '&logFile=' . $fileInfo->getFilename();
1630 $urlOpen = 'ilias.php?baseClass=ilSAHSPresentationGUI' . '&cmd=openLog&ref_id=' . $this->ref_id . '&logFile=' . $fileInfo->getFilename();
1631 $item['date'] = date('Y/m/d H:i:s', $fileInfo->getCTime());
1632 if ($parts['extension'] === "html") {
1633 $item['action'] = $deleteUrl . "&nbsp;<a href=" . $urlDownload . ">" . $s_download . "</a>&nbsp;<a target=_new href=" . $urlOpen . ">" . $s_open . "</a>";
1634 } else {
1635 $item['action'] = $deleteUrl . "&nbsp;<a href=" . $urlDownload . ">" . $s_download . "</a>";
1636 }
1637 if ($parts['extension'] === "html" || $parts['extension'] === "csv") {
1638 $data[] = $item;
1639 }
1640 }
1641 usort($data, "datecmp");
1642 return $data;
1643 }
1644
1645 public function liveLogContent(): void
1646 {
1647 header('Content-Type: text/html; charset=UTF-8');
1648 print file_get_contents($this->logFileName() . ".html");
1649 }
1650
1651 public function debugGUI(): void
1652 {
1653 global $DIC;
1654 $lng = $DIC->language();
1655 $lng->loadLanguageModule("scormdebug");
1656
1657 /* if ($_POST['password'] == $this->slm->getDebugPw()) {
1658 $_SESSION["debug_pw"] = $this->slm->getDebugPw();
1659 }
1660 if ($_SESSION["debug_pw"]!=$this->slm->getDebugPw()) {
1661 $this->tpl = new ilTemplate("tpl.scorm2004.debug_pw.html", false, false, "./Modules/Scorm2004");
1662 $this->tpl->setVariable('SUBMIT', $lng->txt("debugwindow_submit"));
1663 $this->tpl->setVariable('CANCEL', $lng->txt("debugwindow_cancel"));
1664 $this->tpl->setVariable('PASSWORD_ENTER', $lng->txt("debugwindow_password_enter"));
1665 $this->tpl->setVariable('DEBUG_URL','ilias.php?baseClass=ilSAHSPresentationGUI' .'&cmd=debugGUI&ref_id='.$this->ref_id);
1666 } else {*/
1667 $this->tpl = new ilGlobalTemplate("tpl.scorm2004.debug.html", false, false, "./Modules/Scorm2004");
1668 $this->tpl->setVariable('CONSOLE', $lng->txt("debugwindow_console"));
1669 $this->tpl->setVariable('LOGS', $lng->txt("debugwindow_logs"));
1670 $this->tpl->setVariable('COMMENT', $lng->txt("debugwindow_comment"));
1671 $this->tpl->setVariable('COMMENT_ENTER', $lng->txt("debugwindow_comment_enter"));
1672 $this->tpl->setVariable('START_RECORDING', $lng->txt("debugwindow_start_recording"));
1673 $this->tpl->setVariable('STOP_RECORDING', $lng->txt("debugwindow_stop_recording"));
1674 $this->tpl->setVariable('DELETE_LOGFILE', $lng->txt("debugwindow_delete_logfile"));
1675 $this->tpl->setVariable('SUBMISSION_FAILED', $lng->txt("debugwindow_submission_failed"));
1676 $this->tpl->setVariable('SUBMIT', $lng->txt("debugwindow_submit"));
1677 $this->tpl->setVariable('CANCEL', $lng->txt("debugwindow_cancel"));
1678 $this->tpl->setVariable('FILENAME', $lng->txt("debugwindow_filename"));
1679 $this->tpl->setVariable('DATE', $lng->txt("debugwindow_date"));
1680 $this->tpl->setVariable('ACTION', $lng->txt("debugwindow_action"));
1681 $this->tpl->setVariable('RECORD_IMG', ilUtil::getImagePath("record.png", "./Modules/Scorm2004"));
1682 $this->tpl->setVariable('STOP_IMG', ilUtil::getImagePath("stop.png", "./Modules/Scorm2004"));
1683 $this->tpl->setVariable('COMMENT_IMG', ilUtil::getImagePath("comment.png", "./Modules/Scorm2004"));
1684 $logfile = $this->logFileName() . ".html";
1685 $this->tpl->setVariable('LOGFILE', $this->logFileName() . ".html");
1686 $this->tpl->setVariable('FILES_DATA', json_encode($this->getLogFileList($lng->txt("debugwindow_delete"), $lng->txt("debugwindow_download"), $lng->txt("debugwindow_open"))));
1687 $this->tpl->setVariable('PATH_YUI', ilYuiUtil::getLocalPath());
1688 //}
1689 echo $this->tpl->get("DEFAULT", true);
1690 }
1691
1692 private function getLogTemplate(): \ilTemplate
1693 {
1694 return new ilTemplate("tpl.scorm2004.debugtxt.txt", true, true, "Modules/Scorm2004");
1695 }
1696
1700 private function getDebugValues(?bool $test_sco = false): array
1701 {
1702 global $DIC;
1703 $ilDB = $DIC->database();
1704 $ilLog = ilLoggerFactory::getLogger('sc13');
1705 $ini_array = null;
1706 $dvalues = array();
1707 /*
1708 $res = $ilDB->queryF('
1709 SELECT debug_fields
1710 FROM sahs_lm
1711 WHERE id = %s',
1712 array('integer'),
1713 array($this->packageId)
1714 );
1715 $row = $ilDB->fetchAssoc($res);
1716 $debug_fields = $row['debug_fields'];
1717 if ($debug_fields == null) {*/
1718 $debug_fields = parse_ini_file("./Modules/Scorm2004/scripts/rtemain/debug_default.ini", true);
1719 // }
1720 if ($test_sco) {
1721 $ini_array = $debug_fields['test_sco'];
1722 } else {
1723 $ini_array = $debug_fields['normal_sco'];
1724 }
1725 foreach ($ini_array as $key => $value) {
1726 if ($value == 1) {
1727 $dvalues[] = $key;
1728 }
1729 }
1730 return $dvalues;
1731 }
1732
1733 public function postLogEntry(): void
1734 {
1735 global $DIC;
1736 $ilLog = ilLoggerFactory::getLogger('sc13');
1737 $lng = $DIC->language();
1738 $lng->loadLanguageModule("scormdebug");
1739
1740 $logdata = json_decode(file_get_contents('php://input'));
1741 $filename = $this->logFileName();
1742 $tmp_name = $this->logTmpName();
1743
1744 $fh_txt = fopen($filename . ".html", 'a') or die("can't open txt file");
1745 $fh_csv = fopen($filename . ".csv", 'a') or die("can't open csv file");
1746 $fh_tmp = fopen($tmp_name, 'r') or die("can't open tmp file");
1747
1748 //init tmp file
1749 if (filesize($tmp_name) > 0) {
1750 $tmp_content = unserialize(fread($fh_tmp, filesize($tmp_name)));//Check Options - This may causes security issues if the serialized classess arent specified.
1751 } else {
1752 $tmp_content = null;
1753 }
1754
1755 fclose($fh_tmp);
1756
1757 $timestamp = date("d.m.Y H:i", time());
1758
1759 if ($logdata->action != "SUMMARY") {
1760 //reopen for writing
1761 $fh_tmp2 = fopen($tmp_name, 'w') or die("can't open tmp file");
1762
1763 //write tmp
1764 $tmp_content[$logdata->scoid][$logdata->key]['value'] = $logdata->value;
1765 $tmp_content[$logdata->scoid][$logdata->key]['status'] = $logdata->result;
1766 $tmp_content[$logdata->scoid][$logdata->key]['action'] = $logdata->action;
1767
1768 fwrite($fh_tmp2, serialize($tmp_content));
1769 fclose($fh_tmp2);
1770
1771 $errorcode = (int) $logdata->errorcode;
1772 $fixedFailure = false;
1773 $toleratedFailure = false;
1774 $extraErrorDescription = "";
1775 if ($errorcode == 200000) {
1776 $errorcode = 0;
1777 $toleratedFailure = true;
1778 $extraErrorDescription = "tolerated failure";
1779 }
1780 if ($errorcode > 99999) {
1781 $errorcode -= 100000;
1782 $fixedFailure = true;
1783 $extraErrorDescription = " failure corrected by ILIAS";
1784 }
1785 if (strpos($logdata->action, "ANALYZE") === false) {
1786 $errorDescriptions = array("0" => "",
1787 "101" => "General Exeption",
1788 "102" => "General Initialization Failure",
1789 "103" => "Already Initialized",
1790 "104" => "Content Instance Terminated",
1791 "111" => "General Termination Failure",
1792 "112" => "Termination Before Initialization",
1793 "113" => "Termination After Termination",
1794 "122" => "Retrieve Data Before Initialization",
1795 "123" => "Retrieve Data After Termination",
1796 "132" => "Store Data Before Initialization",
1797 "133" => "Store Data After Termination",
1798 "142" => "Commit Before Initialization",
1799 "143" => "Commit After Termination",
1800 "201" => "General Argument Error",
1801 "301" => "General Get Failure",
1802 "351" => "General Set Failure",
1803 "391" => "General Commit Failure",
1804 "401" => "Undefined Data Model Element",
1805 "402" => "Unimplemented Data Model Element",
1806 "403" => "Data Model Element Value Not Initialized",
1807 "404" => "Data Model Element Is Read Only",
1808 "405" => "Data Model Element Is Write Only",
1809 "406" => "Data Model Element Type Mismatch",
1810 "407" => "Data Model Element Value Out Of Range",
1811 "408" => "Data Model Dependency Not Established"
1812 );
1813 $csv_string = $this->packageId . ';"'
1814 . $logdata->scoid . '";"'
1815 . $logdata->scotitle . '";'
1816 . date("d.m.Y H:i", time()) . ';"'
1817 . $logdata->action . '";"'
1818 . $logdata->key . '";"'
1819 . str_replace("\"", "\"\"", $logdata->value) . '";"'
1820 . str_replace("\"", "\"\"", $logdata->result) . '";'
1821 . $errorcode . ';'
1822 . $logdata->timespan . ';"'
1823 . $errorDescriptions[(string) $errorcode] . $extraErrorDescription . '"' . "\n";
1824 fwrite($fh_csv, $csv_string);
1825 }
1826 }
1827
1828 $sqlwrite = false;
1829 if ($logdata->action === "Commit" || $logdata->action === "Terminate") {
1830 $sqlwrite = true;
1831 $sql_data = $this->getNodeData($logdata->scoid);
1832 if (count($sql_data) != 0) {
1833 foreach ($sql_data as $key => $value) {
1834 $sql_string = $this->packageId . ';"'
1835 . $logdata->scoid . '";"'
1836 . $logdata->scotitle . '";'
1837 . $timestamp . ';"SQL";"'
1838 . $key . '";"'
1839 . str_replace("\"", "\"\"", (string) $value) . '";;;;' . "\n";
1840 fwrite($fh_csv, $sql_string);
1841 }
1842 }
1843 }
1844
1845 //delete files
1846 if ($logdata->action === "DELETE") {
1847 $filename = $logdata->value;
1848 $filename = str_replace('/', '', $filename);
1849 $path = $this->logDirectory() . "/" . $filename;
1850 unlink($path);
1851 return;
1852 }
1853
1854 //write TXT
1855 $logtpl = $this->getLogTemplate();
1856 $color = "red";
1857 $importantkey = 1;
1858 $ArGetValues = array('comments_from_lms','completion_threshold','credit','entry','launch_data','learner_id','learner_name','max_time_allowed','mode','scaled_passing_score','time_limit_action','total_time');
1859
1860 switch ($logdata->action) {
1861 case 'SetValue':
1862 if ($logdata->result === "true" && $errorcode == 0) {
1863 $color = "green";
1864 }
1865 if ($color === "green" && $logdata->key === "cmi.exit" && $logdata->value !== "suspend") {
1866 $color = "orange";
1867 }
1868 if ($fixedFailure == false && $errorcode != 406) {
1869 $logdata->value = '"' . $logdata->value . '"';
1870 }
1871 if ($toleratedFailure == true) {
1872 $color = "fuchsia";
1873 }
1874 if ($fixedFailure == true) {
1875 $color = "gray";
1876 }
1877 break;
1878 case 'GetValue':
1879 if ($errorcode == 0) {
1880 $color = "green";
1881 }
1882 break;
1883 case 'Initialize':
1884 if ($errorcode == 0) {
1885 $color = "green";
1886 $logtpl->setCurrentBlock("InitializeStart");
1887 $logtpl->setVariable("SCO-title", $lng->txt("SCO-title"));
1888 $logtpl->setVariable("SCO_TITLE", $logdata->scotitle);
1889 $logtpl->setVariable("SCO-name", $lng->txt("SCO-name"));
1890 $logtpl->setVariable("SCO_NAME", $logdata->scoid);
1891 $logtpl->setVariable("started", $lng->txt("started"));
1892 $logtpl->setVariable("TIMESTAMP", $timestamp);
1893 $logtpl->setVariable("milliseconds", $lng->txt("milliseconds"));
1894 $logtpl->setVariable("API-call", $lng->txt("API-call"));
1895 $logtpl->setVariable("return_value", $lng->txt("return_value"));
1896 $logtpl->setVariable("error", $lng->txt("error"));
1897 $logtpl->parseCurrentBlock();
1898 }
1899 break;
1900 case 'Commit':
1901 if ($errorcode == 0) {
1902 $color = "green";
1903 }
1904 if ($fixedFailure == true) {
1905 $color = "gray";
1906 }
1907 break;
1908 case 'Terminate':
1909 if ($errorcode == 0) {
1910 $color = "green";
1911 }
1912 break;
1913 case 'GetErrorString':
1914 $importantkey = 0;
1915 if ($errorcode == 0) {
1916 $color = "green";
1917 }
1918 break;
1919 case 'GetLastError':
1920 $logtpl->setCurrentBlock("GetLastError");
1921 $logtpl->setVariable("TIMESPAN", $logdata->timespan);
1922 $logtpl->setVariable("RESULT", $logdata->result);
1923 $logtpl->parseCurrentBlock();
1924 break;
1925 case 'GetDiagnostic':
1926 $logtpl->setCurrentBlock("GetDiagnostic");
1927 $logtpl->setVariable("TIMESPAN", $logdata->timespan);
1928 $logtpl->setVariable("KEY", $logdata->key);
1929 $logtpl->setVariable("RESULT", $logdata->result);
1930 $logtpl->parseCurrentBlock();
1931 break;
1932 case 'INFO':
1933 $logtpl->setCurrentBlock("INFO");
1934 $logtpl->setVariable("hint", $lng->txt("hint"));
1935 $logtpl->setVariable("KEY", $lng->txt($logdata->key));
1936 $logtpl->setVariable("VALUE", $logdata->value);
1937 $logtpl->parseCurrentBlock();
1938 break;
1939 case 'COMMENT':
1940 $logtpl->setCurrentBlock("COMMENT");
1941 $logtpl->setVariable("comment", $lng->txt("comment"));
1942 $logtpl->setVariable("generated", $lng->txt("generated"));
1943 $logtpl->setVariable("TIMESTAMP", $timestamp);
1944 $logtpl->setVariable("VALUE", $logdata->value);
1945 $logtpl->parseCurrentBlock();
1946 break;
1947 case 'ANALYZE':
1948 $logtpl->setCurrentBlock("ANALYZE");
1949 if (count($logdata->value) == 0) {
1950 $color = "green";
1951 $logtpl->setVariable("ANALYZE_SUMMARY", $lng->txt("no_missing_API-calls"));
1952 $logtpl->setVariable("VALUE", "");
1953 } else {
1954 $tmpvalue = "SetValue(\"" . implode("\", ... ),<br/>SetValue(\"", $logdata->value) . "\", ... )";
1955 foreach ($ArGetValues as $value) {
1956 $tmpvalue = str_replace("SetValue(\"cmi." . $value . "\", ... )", "GetValue(\"cmi." . $value . "\")", $tmpvalue);
1957 }
1958 $logtpl->setVariable("ANALYZE_SUMMARY", $lng->txt("missing_API-calls"));
1959 $logtpl->setVariable("VALUE", $tmpvalue);
1960 }
1961 $logtpl->setVariable("summary_for_SCO_without_test", $lng->txt("summary_for_SCO_without_test"));
1962 $logtpl->setVariable("generated", $lng->txt("generated"));
1963 $logtpl->setVariable("TIMESTAMP", $timestamp);
1964 $logtpl->setVariable("COLOR", $color);
1965 $logtpl->parseCurrentBlock();
1966 break;
1967 case 'ANALYZETEST':
1968 $logtpl->setCurrentBlock("ANALYZETEST");
1969 if (count($logdata->value) == 0) {
1970 $color = "green";
1971 $logtpl->setVariable("ANALYZE_SUMMARY", $lng->txt("no_missing_API-calls"));
1972 $logtpl->setVariable("VALUE", "");
1973 } else {
1974 $tmpvalue = "SetValue(\"" . implode("\", ... ),<br/>SetValue(\"", $logdata->value) . "\", ... )";
1975 foreach ($ArGetValues as $value) {
1976 $tmpvalue = str_replace("SetValue(\"cmi." . $value . "\", ... )", "GetValue(\"cmi." . $value . "\")", $tmpvalue);
1977 }
1978 $logtpl->setVariable("ANALYZE_SUMMARY", $lng->txt("missing_API-calls"));
1979 $logtpl->setVariable("VALUE", $tmpvalue);
1980 }
1981 $logtpl->setVariable("summary_for_SCO_with_test", $lng->txt("summary_for_SCO_with_test"));
1982 $logtpl->setVariable("generated", $lng->txt("generated"));
1983 $logtpl->setVariable("TIMESTAMP", $timestamp);
1984 $logtpl->setVariable("COLOR", $color);
1985 $logtpl->parseCurrentBlock();
1986 break;
1987 case 'SUMMARY':
1988 $logtpl->setCurrentBlock("SUMMARY");
1989 $logtpl->setVariable("summary_csv", $lng->txt("summary_csv"));
1990 $logtpl->setVariable("TIMESTAMP", $timestamp);
1991 $logtpl->setVariable("summary_download", $lng->txt("summary_download"));
1992 $logtpl->parseCurrentBlock();
1993 break;
1994 default:
1995 $importantkey = 0;
1996 $color = "orange";
1997 break;
1998 }
1999 if ($logdata->action === 'SetValue' || $logdata->action === 'GetValue') {
2000 $logtpl->setCurrentBlock($logdata->action);
2001 $logtpl->setVariable("ACTION", $logdata->action);
2002 $logtpl->setVariable("TIMESPAN", $logdata->timespan);
2003 $logtpl->setVariable("KEY", $logdata->key);
2004 $logtpl->setVariable("VALUE", $logdata->value);
2005 $logtpl->setVariable("RESULT", $logdata->result);
2006 $logtpl->setVariable("ERRORCODE", $errorcode);
2007 $debugfields = $this->getDebugValues(true);
2008 $importantkey = 0;
2009 foreach ($debugfields as $value) {
2010 if ($logdata->key == $value) {
2011 $importantkey = 1;
2012 }
2013 }
2014 $logtpl->setVariable("IMPORTANTKEY", "" . $importantkey);
2015 $logtpl->setVariable("COLOR", $color);
2016 $logtpl->parseCurrentBlock();
2017 } elseif ($logdata->action !== 'INFO' && $logdata->action !== 'ANALYZE' && $logdata->action !== 'ANALYZETEST' && $logdata->action !== 'SUMMARY' && $logdata->action !== 'COMMENT' && $logdata->action !== 'GetDiagnostic' && $logdata->action !== 'GetLastError') {
2018 $logtpl->setCurrentBlock("defaultCall");
2019 $logtpl->setVariable("ACTION", $logdata->action);
2020 $logtpl->setVariable("TIMESPAN", $logdata->timespan);
2021 $logtpl->setVariable("KEY", $logdata->key);
2022 $logtpl->setVariable("VALUE", $logdata->value);
2023 $logtpl->setVariable("RESULT", $logdata->result);
2024 $logtpl->setVariable("ERRORCODE", $errorcode);
2025 $logtpl->setVariable("IMPORTANTKEY", "" . $importantkey);
2026 $logtpl->setVariable("COLOR", $color);
2027 $logtpl->parseCurrentBlock();
2028 }
2029
2030 /*
2031 if ($sqlwrite == true) {
2032 $ilLog->write("SQL WRITE");
2033 $logtpl->setCurrentBlock("SqlLog");
2034 $logtpl->setVariable("SQL_STRING", $sql_text);
2035 $logtpl->parseCurrentBlock();
2036 }
2037 */
2038
2039 //create summary
2040 if ($logdata->action === "SUMMARY") {
2041 $this->createSummary($tmp_content);
2042 }
2043
2044 fwrite($fh_txt, $logtpl->get());
2045 fclose($fh_txt);
2046 fclose($fh_csv);
2047 }
2048
2049 private function getStructureFlat(array $data): void
2050 {
2051 foreach ($data as $i => $value) {
2052 $element = array();
2053 $element['title'] = $value['title'];
2054 $element['id'] = $value['id'];
2055 if ($value['sco'] == 1) {
2056 $element['sco'] = "sco";
2057 } else {
2058 $element['sco'] = "asset";
2059 }
2060 if ($value['href'] != null) {
2061 $this->flat_structure[] = $element;
2062 }
2063 if (isset($value['item']) && $value['item'] != null) {
2064 $this->getStructureFlat($value['item']);
2065 }
2066 }
2067 }
2068
2069 private function createSummary(array $api_data): void
2070 {
2071 global $DIC;
2072 $ilDB = $DIC->database();
2073
2074 $csv_data = null;
2075 //csv columns
2076 $columns_fixed = array('id','title','type','attempted');
2077
2078 $ini_data = parse_ini_file("./Modules/Scorm2004/scripts/rtemain/debug_default.ini", true);
2079 $ini_array = $ini_data['summary'];
2080 $colums_variable = array();
2081 $api_keys = array();
2082
2083 foreach ($ini_array as $key => $value) {
2084 if ($value == 1) {
2085 $colums_variable[] = $key;
2086 $api_keys[] = $key;
2087 $colums_variable[] = "Status";
2088 }
2089 }
2090
2091 $header_array = array_merge($columns_fixed, $colums_variable);
2092
2093 $csv_header = implode(";", $header_array);
2094
2095 //get strcuture
2096 $res = $ilDB->queryF(
2097 'SELECT jsdata FROM cp_package WHERE obj_id = %s',
2098 array('integer'),
2099 array($this->packageId)
2100 );
2101
2102 $packageData = $ilDB->fetchAssoc($res);
2103
2104 $structure = json_decode($packageData['jsdata'], true);
2105
2106
2107 $this->flat_structure = array(); //used for recursion
2108 if (isset($structure['item']) && isset($structure['item']['item'])) {
2109 $this->getStructureFlat($structure['item']['item']);
2110
2111 foreach ($this->flat_structure as $tree_element) {
2112 $csv_data = $csv_data . $tree_element['id'] . ";" . $tree_element['title'] . ";" . $tree_element['sco'] . ";";
2113 if (isset($api_data[$tree_element['id']])) {
2114 $csv_data = $csv_data . "X" . ";";
2115 } else {
2116 $csv_data = $csv_data . ";";
2117 }
2118
2119 //write api data
2120 $id = $tree_element['id'];
2121 foreach ($api_keys as $api_element) {
2122 if (isset($api_data[$id])) {
2123 if (isset($api_data[$id][$api_element])) {
2124 $csv_data = $csv_data . $api_data[$id][$api_element]['value'] . ";" . $api_data[$id][$api_element]['status'] . ";";
2125 } else {
2126 $csv_data = $csv_data . ";;";
2127 }
2128 }
2129 }
2130 $csv_data = $csv_data . "\n";
2131 }
2132 }
2133 $fh = fopen($this->summaryFileName(), "wb"); //changed from w to wb
2134 fwrite($fh, $csv_header . "\n" . $csv_data);
2135 fclose($fh);
2136 unlink($this->logTmpName());
2137 }
2142 // function get_last_visited($a_obj_id, $a_user_id)
2143 // {
2144 // global $DIC;
2145 // $ilDB = $DIC->database();
2146 // $val_set = $ilDB->queryF('SELECT last_visited FROM sahs_user WHERE obj_id = %s AND user_id = %s',
2147 // array('integer','integer'),
2148 // array($a_obj_id,$a_user_id));
2149
2150 // $val_rec = $ilDB->fetchAssoc($val_set);
2151 // return $val_rec["last_visited"];
2152 // }
2153}
2154
2155function datecmp(array $a, array $b): int
2156{
2157 if (strtotime($a['date']) == strtotime($b['date'])) {
2158 return 0;
2159 }
2160 return (strtotime($a['date']) < strtotime($b['date'])) ? 1 : -1;
2161}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$filename
Definition: buildRTE.php:78
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:70
datecmp(array $a, array $b)
Class ilCtrl provides processing control methods.
static makeDir(string $a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
special template class to simplify handling of ITX/PEAR
language handling
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
static getLogger(string $a_component_id)
Get component logger.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getStatus(int $a_packageId, int $a_user_id, bool $auto_last_visited, string $scormType="1.2")
static _lookupObjectId(int $ref_id)
@noinspection ForgottenDebugOutputInspection
writeSharedData(int $sco_node_id)
getDebugValues(?bool $test_sco=false)
getCMIData(int $userId, int $packageId)
getLogFileList(string $s_delete, string $s_download, string $s_open)
get_actual_attempts()
Get number of actual attempts for the user.
readSharedData(int $sco_node_id)
ilObjSCORM2004LearningModule $slm
increase_attemptAndsave_module_version()
Increases attempts by one and saves module_version for this package.
static persistCMIData(int $packageId, int $refId, string $defaultLessonMode, bool $comments, bool $interactions, bool $objectives, bool $time_from_lms, ?string $data=null, ?int $userId=null)
static scormPlayerUnload(int $packageId, int $refId, bool $time_from_lms, ?int $userId=null)
static getIdleValue(bool $fixedMode=false)
Returns the idle time in seconds.
special template class to simplify handling of ITX/PEAR
static getStyleSheetLocation(string $mode="output", string $a_css_name="", string $a_css_location="")
get full style sheet file name (path inclusive) of current user
static getImagePath(string $img, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
static signFolderOfStartFile(string $start_file_path)
static getCookieMaxLifetimeInSeconds()
static getLocalPath(string $a_name="")
Get local path of a YUI js file.
static getLocaljQueryPath()
if(!file_exists(getcwd() . '/ilias.ini.php'))
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: confirmReg.php:20
const CLIENT_ID
Definition: constants.php:41
const ILIAS_WEB_DIR
Definition: constants.php:45
global $DIC
Definition: feed.php:28
$ilUser
Definition: imgupload.php:34
exit
Definition: login.php:28
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:33
$scope
Definition: ltiregstart.php:53
$path
Definition: ltiservices.php:32
$res
Definition: ltiservices.php:69
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:64
if(!array_key_exists('PATH_INFO', $_SERVER)) $config
Definition: metadata.php:85
$i
Definition: metadata.php:41
string $key
Consumer key/client ID value.
Definition: System.php:193
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
global $ilSetting
Definition: privfeed.php:17
$query
$_SERVER['HTTP_HOST']
Definition: raiseError.php:10
$ilErr
Definition: raiseError.php:17
$lng
$packageId
Definition: storeScorm.php:25