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