ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilSCORMOfflineMode.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2011 ILIAS open source, Extended GPL, see docs/LICENSE */
3 //require_once "./Services/Object/classes/class.ilObject.php";
4 
17 {
18  public $type;
19  public $obj_id;
20  public $offlineMode;
21  public $cmd_url;
22  public $lm_cmd_url;
23  public $player12_url;
25  public $som_url;
26 
27  public $sop_dir;
28  public $som_dir;
29  public $scripts_dir;
30 
31  public $sop_index;
32  public $sop_appcache;
33  public $lm_dir;
34  public $lm_index;
35  public $lm_appcache;
37  public $imsmanifest;
38  public $debug = false; // omit caching sop and som files for debugging
39 
46  public function __construct()
47  {
48  global $DIC;
49  $ilias = $DIC['ilias'];
50  $this->ilias = $ilias;
51  $this->id = $_GET['ref_id'];
52  $this->obj_id = ilObject::_lookupObjectId($_GET['ref_id']);
53  include_once "./Modules/ScormAicc/classes/class.ilObjSAHSLearningModule.php";
54  $this->type = ilObjSAHSLearningModule::_lookupSubType($this->obj_id);
55  $this->cmd_url = './ilias.php?baseClass=ilSAHSPresentationGUI&cmd=';
56  $this->lm_cmd_url = './ilias.php?baseClass=ilSAHSPresentationGUI&ref_id=' . $this->id . '&cmd=';
57  $this->lm_info_url = $this->lm_cmd_url . 'infoScreen';
58  $this->player12_url = $this->cmd_url . 'offlineMode_player12';
59  $this->player2004_url = $this->cmd_url . 'offlineMode_player2004';
60  $this->som_url = $this->cmd_url . 'offlineMode_som';
61  $this->offlineMode = 'online';
62  $this->sop_index = './Modules/ScormAicc/sop/sop_index.html';
63  $this->sop_appcache = './Modules/ScormAicc/sop/sop.appcache';
64  $this->sop_dir = './Modules/ScormAicc/templates/sop/';
65  $this->som_dir = './Modules/ScormAicc/templates/som/';
66  $this->scripts_dir = './Modules/ScormAicc/scripts/';
67  $this->images_dir = './templates/default/images/scorm/';
68  $this->pouchdb_js = './libs/bower/bower_components/pouchdb/dist/pouchdb.min.js';
69  $this->jquery_js = './libs/bower/bower_components/jquery/dist/jquery.min.js';
70  $this->bootstrap_js = './libs/bower/bower_components/bootstrap/dist/js/bootstrap.min.js';
71  $this->bootstrap_css = './libs/bower/bower_components/bootstrap/dist/css/bootstrap.min.css';
72  $this->read();
73  }
74 
75  public function getSopManifestEntries()
76  {
77  global $DIC;
78  $log = $DIC['log'];
79  $log->write("getSopManifestEntries ");
80  $manifest_string = "";
81  if (!$this->debug) {
82  // if ($this->type == "scorm2004") {
83  $BASE_DIR = './Modules/Scorm2004/';
84  $manifest_string .= ilUtil::getImagePath("scorm/asset.svg", false) . "\n";
85  $manifest_string .= ilUtil::getImagePath("scorm/completed.svg", false) . "\n";
86  $manifest_string .= ilUtil::getImagePath("scorm/not_attempted.svg", false) . "\n";
87  $manifest_string .= ilUtil::getImagePath("scorm/running.svg", false) . "\n";
88  $manifest_string .= ilUtil::getImagePath("scorm/incomplete.svg", false) . "\n";
89  $manifest_string .= ilUtil::getImagePath("scorm/passed.svg", false) . "\n";
90  $manifest_string .= ilUtil::getImagePath("scorm/failed.svg", false) . "\n";
91  // $manifest_string .= ilUtil::getImagePath("scorm/browsed.svg",false) . "\n";
92  $manifest_string .= ilUtil::getStyleSheetLocation() . "\n";
93  $manifest_string .= $BASE_DIR . 'templates/default/player.css' . "\n";
94  $manifest_string .= $BASE_DIR . 'scripts/buildrte/rte.js' . "\n";
95  $manifest_string .= $BASE_DIR . 'scripts/ilNestedList.js' . "\n";
96  $manifest_string .= iljQueryUtil::getLocaljQueryPath() . "\n";
97  $manifest_string .= $this->player2004_url . "\n";
98  // } else {
99  $manifest_string .= $this->player12_url . "\n";
100  // }
101  $manifest_string .= $this->som_url . "\n";
102  // $log->write("Manifest: ".$manifest_string);
103  $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->sop_dir));
104  foreach ($objects as $name => $object) {
105  if (preg_match('/\/\.+/', $name)) {
106  continue;
107  }
108  //$manifest_string .= preg_replace('/^\./','./Modules/ScormAicc',$name) . "\n"; // for cli
109  $manifest_string .= self::encodeuri($name) . "\n";
110  }
111  $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->som_dir));
112  foreach ($objects as $name => $object) {
113  if (preg_match('/\/\.+/', $name)) {
114  continue;
115  }
116  //$manifest_string .= preg_replace('/^\./','./Modules/ScormAicc',$name) . "\n"; // for cli
117  $manifest_string .= self::encodeuri($name) . "\n";
118  }
119 
120  $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->scripts_dir));
121  foreach ($objects as $name => $object) {
122  if (preg_match('/\/\.+/', $name)) { //UK statt .+ .js und SCORM-Scripts weg
123  continue;
124  }
125  //$manifest_string .= preg_replace('/^\./','./Modules/ScormAicc',$name) . "\n"; // for cli
126  $manifest_string .= self::encodeuri($name) . "\n";
127  }
128  $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->images_dir));
129  foreach ($objects as $name => $object) {
130  if (preg_match('/\/\.+/', $name)) {
131  continue;
132  }
133  //$manifest_string .= preg_replace('/^\./','./Modules/ScormAicc',$name) . "\n"; // for cli
134  $manifest_string .= self::encodeuri($name) . "\n";
135  }
136 
137  $manifest_string .= $this->pouchdb_js . "\n";
138  $manifest_string .= $this->jquery_js . "\n";
139  $manifest_string .= $this->bootstrap_js . "\n";
140  $manifest_string .= $this->bootstrap_css . "\n";
141  }
142  //$log->write($manifest_string);
143  return $manifest_string;
144  }
145 
146  public function getLmManifestEntries()
147  { // ToDo: database support !!
148  global $DIC;
149  $log = $DIC['log'];
150  $log->write("getLmManifestEntries");
151  $this->lm_dir = ilUtil::getWebspaceDir("filesystem") . '/lm_data/lm_' . $this->obj_id;
152  $manifest_string = "";
153  $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->lm_dir));
154  foreach ($objects as $name => $object) {
155  if (preg_match('/\/\.+/', $name)) {
156  continue;
157  }
158  if (preg_match('/\.zip$/', $name)) {
159  continue;
160  }
161  //$manifest_string .= preg_replace('/^\./','./Modules/ScormAicc',$name) . "\n"; // for cli
162  $manifest_string .= self::encodeuri($name) . "\n";
163  }
164  //$log->write($manifest_string);
165  return $manifest_string;
166  }
167 
168  // function il2sop() {
169  public function tracking2sop()
170  {
171  global $DIC;
172  $ilUser = $DIC['ilUser'];
173  $ilias = $DIC['ilias'];
174  // $this->setOfflineMode("il2sop");
175  header('Content-Type: text/javascript; charset=UTF-8');
176 
177  include_once "./Modules/ScormAicc/classes/class.ilObjSAHSLearningModule.php";
178  $ob = new ilObjSAHSLearningModule($this->id);
179  $module_version = $ob->getModuleVersion();
180  $sahs_user = $this->il2sopSahsUser();
181  $support_mail = "";//TODO
182  $scorm_version = "1.2";
183  if ($this->type == "scorm2004") {
184  $scorm_version = "2004";
185  }
186  $tree = "";
187 
188  $learning_progress_enabled = 1;
189  include_once './Services/Object/classes/class.ilObjectLP.php';
190  $olp = ilObjectLP::getInstance($this->obj_id);
191  if ($olp->getCurrentMode() == 0) {
192  $learning_progress_enabled = 0;
193  }
194 
195  $certificate_enabled = 0;
196 
197  $adlact_data = null;
198  $ilias_version = $ilias->getSetting("ilias_version");
199 
200  if ($this->type == 'scorm2004') {
201  include_once "./Modules/Scorm2004/classes/ilSCORM13Player.php";
202  $ob2004 = new ilSCORM13Player();
203  $init_data = json_encode($ob2004->getConfigForPlayer());
204  $resources = json_decode($ob2004->getCPDataInit());
205  $cmi = $ob2004->getCMIData($ilUser->getID(), $this->obj_id);
206  $max_attempt = $ob2004->get_max_attempts();
207  $adlact_data = json_decode($ob2004->getADLActDataInit());
208  //$globalobj_data = $ob2004->readGObjectiveInit();
209  } else {
210  include_once "./Modules/ScormAicc/classes/SCORM/class.ilObjSCORMInitData.php";
211  $slm_obj = new ilObjSCORMLearningModule($_GET["ref_id"]);
212  $init_data = ilObjSCORMInitData::getIliasScormVars($slm_obj);
213  $resources = json_decode(ilObjSCORMInitData::getIliasScormResources($this->obj_id));
214  $tree = json_decode(ilObjSCORMInitData::getIliasScormTree($this->obj_id));
215  $cmi = json_decode(ilObjSCORMInitData::getIliasScormData($this->obj_id));
216  $max_attempt = ilObjSCORMInitData::get_max_attempts($this->obj_id);
217  }
218  //UK max_attempt weg!
219  // if ($max_attempt == null) $max_attempt = 0;
220  $result = array(
221  'client_data' => array(
222  $support_mail
223  ),
224  'user_data' => $this->il2sopUserData(),
225  'lm' => array(
226  ilObject::_lookupTitle($this->obj_id),
227  ilObject::_lookupDescription($this->obj_id),
228  $scorm_version,
229  1,//active
230  $init_data,
231  $resources,
232  $tree,
233  $module_version,
234  "", //offline_zip_created!!!!!!!!
235  $learning_progress_enabled,
236  $certificate_enabled,
237  $max_attempt,
238  $adlact_data,
239  $ilias_version
240  ),
241  'sahs_user' => $sahs_user,
242  'cmi' => $cmi
243  );
244 
245  print(json_encode($result));
246  }
247 
248  public function getClientIdSop()
249  {
250  $iliasDomain = substr(ILIAS_HTTP_PATH, 7);
251  if (substr($iliasDomain, 0, 1) == "\/") {
252  $iliasDomain = substr($iliasDomain, 1);
253  }
254  if (substr($iliasDomain, 0, 4) == "www.") {
255  $iliasDomain = substr($iliasDomain, 4);
256  }
257  return $iliasDomain . ';' . CLIENT_ID;
258  }
259 
260  public function il2sopUserData()
261  {
262  global $DIC;
263  $ilUser = $DIC['ilUser'];
264  return array(
265  $ilUser->getLogin(),
266  "",
267  $ilUser->getFirstname(),
268  $ilUser->getLastname(),
269  $ilUser->getUTitle(),
270  $ilUser->getGender(),
271  $ilUser->getID()
272  );
273  }
274  public function il2sopSahsUser()
275  {
276  global $DIC;
277  $ilDB = $DIC['ilDB'];
278  $ilUser = $DIC['ilUser'];
279  $package_attempts = 0;
280  $module_version = 1;//if module_version in sop is different...
281  $last_visited = "";
282  $first_access = null;
283  $last_access = null;
284  $last_status_change = null;
285  $total_time_sec = null;
286  $sco_total_time_sec = 0;
287  $status = 0;
288  $percentage_completed = 0;
289  $user_data = "";
290 
291  global $DIC;
292  $ilDB = $DIC['ilDB'];
293  $ilUser = $DIC['ilUser'];
294  $res = $ilDB->queryF(
295  'SELECT * FROM sahs_user WHERE obj_id=%s AND user_id=%s',
296  array('integer','integer'),
297  array($this->obj_id,$ilUser->getID())
298  );
299  while ($row = $ilDB->fetchAssoc($res)) {
300  $package_attempts = $row['package_attempts'];
301  $module_version = $row['module_version'];
302  $last_visited = $row['last_visited'];
303  if ($row['first_access'] != null) {
304  $first_access = strtotime($row['first_access']) * 1000;//check Oracle!
305  }
306  if ($row['last_access'] != null) {
307  $last_access = strtotime($row['last_access']) * 1000;//check Oracle!
308  }
309  $total_time_sec = $row['total_time_sec'];
310  $sco_total_time_sec = $row['sco_total_time_sec'];
311  $status = $row['status'];
312  $percentage_completed = $row['percentage_completed'];
313  }
314  if ($first_access == null) {
315  include_once './Services/Tracking/classes/class.ilChangeEvent.php';
316  $all = ilChangeEvent::_lookupReadEvents($this->obj_id, $ilUser->getID());
317  foreach ($all as $event) {
318  $first_access = strtotime($event['first_access']) * 1000;//
319  }
320  }
321  return array($package_attempts, $module_version, $last_visited, $first_access, $last_access, $last_status_change, $total_time_sec, $sco_total_time_sec, $status, $percentage_completed, $user_data);
322  }
323 
324  public function sop2il()
325  {
326  // sleep(5);
327  global $DIC;
328  $ilDB = $DIC['ilDB'];
329  $ilUser = $DIC['ilUser'];
330  $in = file_get_contents("php://input");
331  $GLOBALS['DIC']['ilLog']->write($in);
332  $ret = array('msg' => array(),'err' => array());
333 
334  if (!$in || $in == "") {
335  $ret['err'][] = "no post data recieved";
336  print(json_encode($ret));
337  exit;
338  }
339  $userId = $ilUser->getID();
340  $result = true;
341 
342  if ($this->type == 'scorm2004') {
343  $lm_set = $ilDB->queryF('SELECT default_lesson_mode, interactions, objectives, comments, time_from_lms FROM sahs_lm WHERE id = %s', array('integer'), array($this->obj_id));
344  while ($lm_rec = $ilDB->fetchAssoc($lm_set)) {
345  $defaultLessonMode = ($lm_rec["default_lesson_mode"]);
346  $interactions = (ilUtil::yn2tf($lm_rec["interactions"]));
347  $objectives = (ilUtil::yn2tf($lm_rec["objectives"]));
348  $comments = (ilUtil::yn2tf($lm_rec["comments"]));
349  $time_from_lms = (ilUtil::yn2tf($lm_rec["time_from_lms"]));
350  }
351  include_once './Modules/Scorm2004/classes/class.ilSCORM2004StoreData.php';
352  $data = json_decode($in);
353  $GLOBALS['DIC']['ilLog']->write('cmi_count=' . count($data->cmi));
354  for ($i = 0; $i < count($data->cmi); $i++) {
355  if ($result == true) {
356  //$a_r=array();
357  $cdata = $data->cmi[$i];
359  $userId,
360  $this->obj_id,
361  $data->cmi[$i],//json_decode($data->cmi[$i]),
362  $comments,
363  $interactions,
364  $objectives
365  );
366  if (!is_array($a_r)) {
367  $result = false;
368  }
369  }
370  }
371  if ($result == true) {
372  $result = ilSCORM2004StoreData::syncGlobalStatus($userId, $this->obj_id, $data, $data->now_global_status, $time_from_lms);
373  }
374  } else {
375  include_once "./Modules/ScormAicc/classes/SCORM/class.ilObjSCORMTracking.php";
376  $data = json_decode($in);
377  $result = ilObjSCORMTracking::storeJsApiCmi($userId, $this->obj_id, $data);
378  if ($result == true) {
379  $result = ilObjSCORMTracking::syncGlobalStatus($userId, $this->obj_id, $data, $data->now_global_status);
380  }
381  }
382  if ($result == true) {
383  $result = self::scormPlayerUnloadForSOP2il($data);
384  }
385 
386  if ($result == false) {
387  $ret['err'][] = "invalid post data recieved";
388  } else {
389  $ret['msg'][] = "post data recieved";
390  }
391  header('Content-Type: text/plain; charset=UTF-8');
392  print json_encode($ret);
393  }
394 
396  {
397  global $DIC;
398  $ilDB = $DIC['ilDB'];
399  $ilUser = $DIC['ilUser'];
400  $first_access = null;
401  if ($data->first_access != null) {
402  $first_access = date('Y-m-d H:i:s', round($data->first_access / 1000));
403  }
404  $last_access = null;
405  $i_last_access = null;
406  if ($data->last_access != null) {
407  $i_last_access = round($data->last_access / 1000);
408  $last_access = date('Y-m-d H:i:s', $i_last_access);
409  include_once("./Services/Tracking/classes/class.ilChangeEvent.php");
410  ilChangeEvent::_updateAccessForScormOfflinePlayer($this->obj_id, $ilUser->getId(), $i_last_access, $first_access);
411  }
412  $last_status_change = null;
413  if ($data->last_status_change != null) {
414  $last_status_change = date('Y-m-d H:i:s', round($data->last_status_change / 1000));
415  }
416  $GLOBALS['DIC']['ilLog']->write('first_access=' . $first_access);
417  $res = $ilDB->queryF(
418  'UPDATE sahs_user SET first_access=%s, last_access=%s, last_status_change=%s, last_visited=%s, module_version=%s WHERE obj_id=%s AND user_id=%s',
419  array('timestamp','timestamp','timestamp','text','integer','integer','integer'),
420  array($first_access,$last_access,$last_status_change,$data->last_visited,$data->module_version, $this->obj_id,$ilUser->getId())
421  );
422 
423  //populate last_status_change
424  return true;
425  }
426 
427  //offlineMode: offline, online, il2sop, sop2il
428  public function setOfflineMode($a_mode)
429  {
430  global $DIC;
431  $ilDB = $DIC['ilDB'];
432  $ilUser = $DIC['ilUser'];
433  $res = $ilDB->queryF(
434  'UPDATE sahs_user SET offline_mode=%s WHERE obj_id=%s AND user_id=%s',
435  array('text','integer','integer'),
436  array($a_mode, $this->obj_id,$ilUser->getId())
437  );
438  $this->offlineMode = $a_mode;
439  }
440  public function getOfflineMode()
441  {
442  return $this->offlineMode;
443  }
444 
445  private function read()
446  {
447  global $DIC;
448  $ilDB = $DIC['ilDB'];
449  $ilUser = $DIC['ilUser'];
450  $res = $ilDB->queryF(
451  'SELECT offline_mode FROM sahs_user WHERE obj_id=%s AND user_id=%s',
452  array('integer','integer'),
453  array($this->obj_id,$ilUser->getId())
454  );
455  while ($row = $ilDB->fetchAssoc($res)) {
456  if ($row['offline_mode'] != null && $row['offline_mode'] != '') {
457  $this->offlineMode = $row['offline_mode'];
458  } else {
459  $this->offlineMode = "online";
460  }
461  }
462  }
463 
464  public static function checkIfAnyoneIsInOfflineMode($obj_id)
465  {
466  global $DIC;
467  $ilDB = $DIC['ilDB'];
468  $res = $ilDB->queryF(
469  "SELECT count(*) cnt FROM sahs_user WHERE obj_id=%s AND offline_mode = 'offline'",
470  array('integer'),
471  array($obj_id)
472  );
473  $val_rec = $ilDB->fetchAssoc($res);
474  if ($val_rec["cnt"] == 0) {
475  return false;
476  }
477  return true;
478  }
479 
480  public static function usersInOfflineMode($obj_id)
481  {
482  global $DIC;
483  $ilDB = $DIC['ilDB'];
484  $users = array();
485  $res = $ilDB->queryF(
486  "SELECT user_id, lastname, firstname FROM sahs_user, usr_data "
487  . "WHERE sahs_user.obj_id=%s AND sahs_user.offline_mode = 'offline' AND sahs_user.user_id=usr_data.usr_id",
488  array('integer'),
489  array($obj_id)
490  );
491  while ($row = $ilDB->fetchAssoc($res)) {
492  $users[] = $row;
493  }
494  return $users;
495  }
496 
497  public static function stopOfflineModeForUser($obj_id, $user_id)
498  {
499  global $DIC;
500  $ilDB = $DIC['ilDB'];
501  $res = $ilDB->queryF(
502  "UPDATE sahs_user SET offline_mode='online' WHERE obj_id=%s AND user_id=%s",
503  array('integer','integer'),
504  array($obj_id,$user_id)
505  );
506  }
507 
508  public static function encodeuri($path)
509  {
510  return implode('/', array_map('rawurlencode', explode('/', $path)));
511  }
512 }
static getIliasScormData($a_packageId)
static syncGlobalStatus($userId, $packageId, $data, $new_global_status, $time_from_lms)
static storeJsApiCmi($user_id, $obj_id, $data)
$path
Definition: aliased.php:25
static getIliasScormResources($a_packageId)
static stopOfflineModeForUser($obj_id, $user_id)
$result
global $DIC
Definition: saml.php:7
static getStyleSheetLocation($mode="output", $a_css_name="", $a_css_location="")
get full style sheet file name (path inclusive) of current user
$_GET["client_id"]
static usersInOfflineMode($obj_id)
static _lookupTitle($a_id)
lookup object title
$log
Definition: sabredav.php:21
static checkIfAnyoneIsInOfflineMode($obj_id)
static _lookupSubType($a_obj_id)
lookup subtype id (scorm, )
static _lookupObjectId($a_ref_id)
lookup object id
static getIliasScormVars($slm_obj)
static _updateAccessForScormOfflinePlayer($obj_id, $usr_id, $i_last_access, $t_first_access)
_updateAccessForScormOfflinePlayer needed to synchronize last_access and first_access when learning m...
foreach($_POST as $key=> $value) $res
static get_max_attempts($a_packageId)
Get max.
static getImagePath($img, $module_path="", $mode="output", $offline=false)
get image path (for images located in a template directory)
static _lookupDescription($a_id)
lookup object description
$ilUser
Definition: imgupload.php:18
redirection script todo: (a better solution should control the processing via a xml file) ...
static _lookupReadEvents($obj_id, $usr_id=null)
Reads all read events which occured on the object which happened after the last time the user caught ...
$users
Definition: authpage.php:44
$row
if(php_sapi_name() !='cli') $in
Definition: Utf8Test.php:37
exit
Definition: backend.php:16
static setCMIData($userId, $packageId, $data, $getComments, $getInteractions, $getObjectives)
$lm_set
global $ilDB
$ret
Definition: parser.php:6
$i
Definition: disco.tpl.php:19
static syncGlobalStatus($userId, $packageId, $data, $new_global_status)
Class ilSCORMOfflineMode.
static yn2tf($a_yn)
convert "y"/"n" to true/false
static getLocaljQueryPath()
static getInstance($a_obj_id)
static getWebspaceDir($mode="filesystem")
get webspace directory
Class ilObjSCORMLearningModule.
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
Class ilObjSCORMLearningModule.
static getIliasScormTree($a_packageId)
$data
Definition: bench.php:6