ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilObjSCORM2004LearningModule.php
Go to the documentation of this file.
1 <?php
2 
3 /* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
4 
5 require_once "./Modules/ScormAicc/classes/class.ilObjSCORMLearningModule.php";
6 
16 {
18 // var $meta_data;
19 
20  const CONVERT_XSL = './Modules/Scorm2004/templates/xsl/op/scorm12To2004.xsl';
21  const WRAPPER_HTML = './Modules/Scorm2004/scripts/converter/GenericRunTimeWrapper1.0_aadlc/GenericRunTimeWrapper.htm';
22  const WRAPPER_JS = './Modules/Scorm2004/scripts/converter/GenericRunTimeWrapper1.0_aadlc/SCOPlayerWrapper.js';
23 
30  function ilObjSCORM2004LearningModule($a_id = 0, $a_call_by_reference = true)
31  {
32  $this->type = "sahs";
33  parent::ilObject($a_id,$a_call_by_reference);
34  }
35 
36 
43  function validate($directory)
44  {
45  //$this->validator =& new ilObjSCORMValidator($directory);
46  //$returnValue = $this->validator->validate();
47  return true;
48  }
49 
50 
55  function readObject()
56  {
57  global $ilias, $lng ,$ilDB;
58 
59  //check for MYSQL 4.1 and json_encode,json_decode
60  if (!function_exists('json_encode') || !function_exists('json_decode') || ($ilDB->getDBType() == 'mysql' && !$ilDB->isMysql4_1OrHigher())) {
61  $ilias->raiseError($lng->txt('scplayer_phpmysqlcheck'),$ilias->error_obj->WARNING);
62  }
63 
64  // the seems_utf8($str) function
65  include_once("include/inc.utf8checker.php");
66  $needs_convert = false;
67 
68  // convert imsmanifest.xml file in iso to utf8 if needed
69  // include_once("include/inc.convertcharset.php");
70  $manifest_file = $this->getDataDirectory()."/imsmanifest.xml";
71 
72  // check if manifestfile exists and space left on device...
73  $check_for_manifest_file = is_file($manifest_file);
74 
75 
76 
77  // if no manifestfile
78  if (!$check_for_manifest_file)
79  {
80  $this->ilias->raiseError($this->lng->txt("Manifestfile $manifest_file not found!"), $this->ilias->error_obj->MESSAGE);
81  return;
82  }
83 
84 
85  if ($check_for_manifest_file)
86  {
87  $manifest_file_array = file($manifest_file);
88 
89  foreach($manifest_file_array as $mfa)
90  {
91 
92  if (seems_not_utf8($mfa))
93  {
94  $needs_convert = true;
95  break;
96  }
97  }
98 
99 
100 
101  // to copy the file we need some extraspace, counted in bytes *2 ... we need 2 copies....
102  $estimated_manifest_filesize = filesize($manifest_file) * 2;
103 
104  // i deactivated this, because it seems to fail on some windows systems (see bug #1795)
105  //$check_disc_free = disk_free_space($this->getDataDirectory()) - $estimated_manifest_filesize;
106  $check_disc_free = 2;
107  }
108 
109 
110  // if $manifest_file needs to be converted to UTF8
111  if ($needs_convert)
112  {
113  // if file exists and enough space left on device
114  if ($check_for_manifest_file && ($check_disc_free > 1))
115  {
116 
117  // create backup from original
118  if (!copy($manifest_file, $manifest_file.".old"))
119  {
120  echo "Failed to copy $manifest_file...<br>\n";
121  }
122 
123  // read backupfile, convert each line to utf8, write line to new file
124  // php < 4.3 style
125  $f_write_handler = fopen($manifest_file.".new", "w");
126  $f_read_handler = fopen($manifest_file.".old", "r");
127  while (!feof($f_read_handler))
128  {
129  $zeile = fgets($f_read_handler);
130  //echo mb_detect_encoding($zeile);
131  fputs($f_write_handler, utf8_encode($zeile));
132  }
133  fclose($f_read_handler);
134  fclose($f_write_handler);
135 
136  // copy new utf8-file to imsmanifest.xml
137  if (!copy($manifest_file.".new", $manifest_file))
138  {
139  echo "Failed to copy $manifest_file...<br>\n";
140  }
141 
142  if (!@is_file($manifest_file))
143  {
144  $this->ilias->raiseError($this->lng->txt("cont_no_manifest"),
145  $this->ilias->error_obj->WARNING);
146  }
147  }
148  else
149  {
150  // gives out the specific error
151 
152  if (!($check_disc_free > 1))
153  $this->ilias->raiseError($this->lng->txt("Not enough space left on device!"),$this->ilias->error_obj->MESSAGE);
154  return;
155  }
156 
157  }
158  else
159  {
160  // check whether file starts with BOM (that confuses some sax parsers, see bug #1795)
161  $hmani = fopen($manifest_file, "r");
162  $start = fread($hmani, 3);
163  if (strtolower(bin2hex($start)) == "efbbbf")
164  {
165  $f_write_handler = fopen($manifest_file.".new", "w");
166  while (!feof($hmani))
167  {
168  $n = fread($hmani, 900);
169  fputs($f_write_handler, $n);
170  }
171  fclose($f_write_handler);
172  fclose($hmani);
173 
174  // copy new utf8-file to imsmanifest.xml
175  if (!copy($manifest_file.".new", $manifest_file))
176  {
177  echo "Failed to copy $manifest_file...<br>\n";
178  }
179  }
180  else
181  {
182  fclose($hmani);
183  }
184  }
185 
186  //validate the XML-Files in the SCORM-Package
187  if ($_POST["validate"] == "y")
188  {
189  if (!$this->validate($this->getDataDirectory()))
190  {
191  $this->ilias->raiseError("<b>Validation Error(s):</b><br>".$this->getValidationSummary(),
192  $this->ilias->error_obj->WARNING);
193  }
194  }
195 
196 
197  //check for SCORM 1.2
198  $this->convert_1_2_to_2004($manifest_file);
199 
200  // start SCORM 2004 package parser/importer
201  include_once ("./Modules/Scorm2004/classes/ilSCORM13Package.php");
202  $newPack = new ilSCORM13Package();
203  if ($_POST["editable"] == "y")
204  return $newPack->il_importLM($this,$this->getDataDirectory());
205  return $newPack->il_import($this->getDataDirectory(),$this->getId(),$this->ilias,$_POST["validate"]);
206  }
207 
208 
209  public function fixReload() {
210  $out = file_get_contents($this->imsmanifestFile);
211  $check ='/xmlns="http:\/\/www.imsglobal.org\/xsd\/imscp_v1p1"/';
212  $replace="xmlns=\"http://www.imsproject.org/xsd/imscp_rootv1p1p2\"";
213  $out=preg_replace($check, $replace, $out);
214  file_put_contents($this->imsmanifestFile, $out);
215  }
216 
217 
218  public function convert_1_2_to_2004($manifest) {
219  global $ilDB, $ilLog;
220 
221  ##check manifest-file for version. Check for schemaversion as this is a required element for SCORM 2004
222  ##accept 2004 3rd Edition an CAM 1.3 as valid schemas
223 
224  //set variables
225  $this->packageFolder=$this->getDataDirectory();
226  $this->imsmanifestFile=$manifest;
227  $doc = new DomDocument();
228 
229  //fix reload errors before loading
230  $this->fixReload();
231  $doc->load($this->imsmanifestFile);
232  $elements = $doc->getElementsByTagName("schemaversion");
233  $schema=$elements->item(0)->nodeValue;
234  if (strtolower(trim($schema))=="cam 1.3" || strtolower(trim($schema))=="2004 3rd edition") {
235  //no conversion
236  $this->converted=false;
237  return true;
238 
239  } else {
240  $this->converted=true;
241  //convert to SCORM 2004
242 
243  //check for broken SCORM 1.2 manifest file (missing organization default-common error in a lot of manifest files)
244  $organizations = $doc->getElementsByTagName("organizations");
245  $default=$organizations->item(0)->getAttribute("default");
246  if ($default=="" || $default==null) {
247  //lookup identifier
248  $organization = $doc->getElementsByTagName("organization");
249  $ident=$organization->item(0)->getAttribute("identifier");
250  $organizations->item(0)->setAttribute("default",$ident);
251  }
252 
253  //validate the fixed mainfest. If it's still not valid, don't transform an throw error
254 
255 
256  //first copy wrappers
257  $wrapperdir=$this->packageFolder."/GenericRunTimeWrapper1.0_aadlc";
258  mkdir($wrapperdir);
259  copy(self::WRAPPER_HTML,$wrapperdir."/GenericRunTimeWrapper.htm");
260  copy(self::WRAPPER_JS,$wrapperdir."/SCOPlayerWrapper.js");
261 
262  //backup manifestfile
263  $this->backupManifest=$this->packageFolder."/imsmanifest.xml.back";
264  $ret=copy($this->imsmanifestFile,$this->backupManifest);
265 
266  //transform manifest file
267  $this->totransform = $doc;
268  $ilLog->write("SCORM: about to transform to SCORM 2004");
269 
270  $xsl = new DOMDocument;
271  $xsl->async = false;
272  $xsl->load(self::CONVERT_XSL);
273  $prc = new XSLTProcessor;
274  $r = @$prc->importStyleSheet($xsl);
275 
276  file_put_contents($this->imsmanifestFile, $prc->transformToXML($this->totransform));
277 
278  $ilLog->write("SCORM: Transoformation completed");
279  return true;
280  }
281 
282  }
283 
291  public static function _lookupLastAccess($a_obj_id, $a_usr_id)
292  {
293  global $ilDB;
294 
295  $result = $ilDB->queryF('
296  SELECT MAX(c_timestamp) last_access
297  FROM cmi_node, cp_node
298  WHERE cmi_node.cp_node_id = cp_node.cp_node_id
299  AND cp_node.slm_id = %s
300  AND user_id = %s
301  ORDER BY c_timestamp DESC',
302  array('integer', 'integer'),
303  array($a_obj_id, $a_usr_id));
304  if ($ilDB->numRows($result))
305  {
306  $row = $ilDB->fetchAssoc($result);
307  return $row["last_access"];
308  }
309 
310  return "";
311  }
312 
316  function getTrackedUsers($a_search)
317  {
318  global $ilUser, $ilDB, $ilUser;
319 
320  $sco_set = $ilDB->queryF('
321  SELECT DISTINCT user_id,MAX(c_timestamp) last_access
322  FROM cmi_node, cp_node
323  WHERE cmi_node.cp_node_id = cp_node.cp_node_id
324  AND cp_node.slm_id = %s
325  GROUP BY user_id',
326  array('integer'),
327  array($this->getId()));
328 
329  $items = array();
330  $temp = array();
331 
332  while($sco_rec = $ilDB->fetchAssoc($sco_set))
333  {
334  $name = ilObjUser::_lookupName($sco_rec["user_id"]);
335  if ($sco_rec['last_access'] != 0) {
336  $sco_rec['last_access'] = ilDatePresentation::formatDate(new ilDateTime($sco_rec['last_access'],IL_CAL_DATETIME));
337 
338  } else {
339  $sco_rec['last_access'] = "";
340  }
341  if (ilObject::_exists($sco_rec['user_id']) && ilObject::_lookUpType($sco_rec['user_id'])=="usr" ) {
342  $user = new ilObjUser($sco_rec['user_id']);
343  $temp = array("user_full_name" => $name["lastname"].", ".
344  $name["firstname"]." [".ilObjUser::_lookupLogin($sco_rec["user_id"])."]",
345  "user_id" => $sco_rec["user_id"],"last_access" => $sco_rec['last_access'],
346  "user_id" => $sco_rec["user_id"],"last_access" => $sco_rec['last_access'],
347  "version"=> $this->getModuleVersionForUser($sco_rec["user_id"]),
348  "attempts" => $this->getAttemptsForUser($sco_rec["user_id"]),
349  "username" => $user->getLastname().", ".$user->getFirstname()
350  );
351  if ($a_search != "" && (strpos(strtolower($user->getLastname()), strtolower($a_search)) !== false || strpos(strtolower($user->getFirstname()), strtolower($a_search)) !== false ) ) {
352  $items[] = $temp;
353  } else if ($a_search == "") {
354  $items[] = $temp;
355  }
356  }
357  }
358 
359  return $items;
360  }
361 
365  function deleteTrackingDataOfUsers($a_users)
366  {
367  global $ilDB;
368 
369  foreach($a_users as $user)
370  {
371  $res = $ilDB->manipulateF(
372  'DELETE FROM cmi_node WHERE user_id = %s'.
373  'AND cp_node_id IN (SELECT cp_node_id FROM cp_node WHERE slm_id = %s)',
374  array('integer', 'integer'),
375  array($user, $this->getId()));
376 
377  // update learning progress
378  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
379  ilLPStatusWrapper::_updateStatus($this->getId(), $user);
380  }
381  }
382 
383 
384  function getTrackedItems()
385  {
386  global $ilUser, $ilDB, $ilUser;
387 
388  $sco_set = $ilDB->queryF('
389  SELECT DISTINCT cmi_node.cp_node_id id
390  FROM cp_node, cmi_node
391  WHERE slm_id = %s
392  AND cp_node.cp_node_id = cmi_node.cp_node_id
393  ORDER BY cp_node.cp_node_id ',
394  array('integer'),
395  array($this->getId()));
396 
397  $items = array();
398 
399  while($sco_rec = $ilDB->fetchAssoc($sco_set))
400  {
401  $item['id']=$sco_rec["id"];
402  $item['title']=self::_lookupItemTitle($sco_rec["id"]);
403  $items[count($items)] =$item;
404 
405  }
406  return $items;
407  }
408 
409 
410  function getTrackingDataAgg($a_sco_id, $raw = false)
411  {
412  global $ilDB;
413 
414  $scos = array();
415  $data = array();
416  //get all SCO's of this object
417 
418  $val_set = $ilDB->queryF(
419  'SELECT cp_node_id FROM cp_node
420  WHERE nodename = %s
421  AND cp_node.slm_id = %s',
422  array('text', 'integer'),
423  array('item',$this->getId())
424  );
425  while($val_rec = $ilDB->fetchAssoc($val_set))
426  {
427  array_push($scos,$val_rec['cp_node_id']);
428  }
429 
430  foreach ($scos as $sco)
431  {
432  $data_set = $ilDB->queryF('
433  SELECT c_timestamp last_access, session_time, success_status, completion_status,
434  c_raw, cp_node_id
435  FROM cmi_node
436  WHERE cp_node_id = %s
437  AND user_id = %s',
438  array('integer','integer'),
439  array($sco,$_GET["user_id"])
440  );
441 
442  while($data_rec = $ilDB->fetchAssoc($data_set))
443  {
444  if ($data_rec["success_status"]!="") {
445  $status = $data_rec["success_status"];
446  } else {
447  if ($data_rec["completion_status"]=="") {
448  $status="unknown";
449  } else {
450  $status = $data_rec["completion_status"];
451  }
452  }
453  if(!$raw)
454  {
455  $time = ilFormat::_secondsToString(self::_ISODurationToCentisec($data_rec["session_time"])/100);
456  $score = $data_rec["c_raw"];
457  $title = self::_lookupItemTitle($data_rec["cp_node_id"]);
458  $last_access=ilDatePresentation::formatDate(new ilDateTime($data_rec['last_access'],IL_CAL_UNIX));
459  $data[] = array("user_id" => $data_rec["user_id"],
460  "score" => $score, "time" => $time, "status" => $status,"last_access"=>$last_access,"title"=>$title);
461  }
462  else
463  {
464  $data_rec["session_time"] = self::_ISODurationToCentisec($data_rec["session_time"])/100;
465  $data[$data_rec["cp_node_id"]] = $data_rec;
466  }
467  }
468  }
469 
470 
471  return $data;
472  }
473 
477  function getAttemptsForUser($a_user_id){
478  global $ilDB;
479 
480  $val_set = $ilDB->queryF('
481  SELECT * FROM cmi_custom
482  WHERE user_id = %s
483  AND sco_id = %s
484  AND lvalue = %s
485  AND obj_id = %s',
486  array('integer','integer', 'text','integer'),
487  array($a_user_id, 0,'package_attempts',$this->getId()));
488 
489  $val_rec = $ilDB->fetchAssoc($val_set);
490 
491  $val_rec["rvalue"] = str_replace("\r\n", "\n", $val_rec["rvalue"]);
492  if ($val_rec["rvalue"] == null) {
493  $val_rec["rvalue"]="";
494  }
495 
496  return $val_rec["rvalue"];
497  }
498 
499 
503  function getModuleVersionForUser($a_user_id){
504  global $ilDB;
505 
506  $val_set = $ilDB->queryF('
507  SELECT * FROM cmi_custom
508  WHERE user_id = %s
509  AND sco_id = %s
510  AND lvalue = %s
511  AND obj_id = %s',
512  array('integer','integer', 'text','integer'),
513  array($a_user_id, 0,'module_version',$this->getId()));
514 
515  $val_rec = $ilDB->fetchAssoc($val_set);
516 
517  $val_rec["rvalue"] = str_replace("\r\n", "\n", $val_rec["rvalue"]);
518  if ($val_rec["rvalue"] == null) {
519  $val_rec["rvalue"]="";
520  }
521  return $val_rec["rvalue"];
522  }
523 
524 
525 
526  function exportSelected($a_exportall = 0, $a_user = array())
527  {
528  global $ilDB, $ilUser;
529 
530  $scos = array();
531 
532  //get all SCO's of this object
533  $query = 'SELECT cp_node.cp_node_id '
534  . 'FROM cp_node, cp_resource, cp_item '
535  . 'WHERE cp_item.cp_node_id = cp_node.cp_node_id '
536  . 'AND cp_item.resourceid = cp_resource.id AND scormtype = %s '
537  . 'AND nodename = %s AND cp_node.slm_id = %s';
538  $res = $ilDB->queryF(
539  $query,
540  array('text', 'text', 'integer'),
541  array('sco', 'item', $this->getId())
542  );
543  while($row = $ilDB->fetchAssoc($res))
544  {
545  $scos[] = $row['cp_node_id'];
546  }
547 
548  $csv = null;
549 
550  //a module is completed when all SCO's are completed
551  $user_array = array();
552 
553  if($a_exportall == 1)
554  {
555  $query = 'SELECT user_id '
556  . 'FROM cmi_node, cp_node '
557  . 'WHERE cmi_node.cp_node_id = cp_node.cp_node_id AND cp_node.slm_id = %s '
558  . 'GROUP BY user_id';
559  $res = $ilDB->queryF(
560  $query,
561  array('integer'),
562  array($this->getId())
563  );
564  while($row = $ilDB->fetchAssoc($res))
565  {
566  $user_array[] = $row['user_id'];
567  }
568  }
569  else
570  {
571  $user_array = $a_user;
572  }
573 
574  foreach($user_array as $user)
575  {
576  $scos_c = $scos;
577  //copy SCO_array
578  //check if all SCO's are completed
579  for($i = 0; $i < count($scos); $i++)
580  {
581  $query = 'SELECT * FROM cmi_node '
582  . 'WHERE user_id = %s AND cp_node_id = %s '
583  . 'AND completion_status = %s OR success_status = %s';
584  $res = $ilDB->queryF(
585  $query,
586  array('integer', 'integer', 'text', 'text'),
587  array($user, $scos[$i], 'completed', 'passed')
588  );
589 
590  $data = $ilDB->fetchAssoc($res);
591  if(is_array($data) && count($data))
592  {
593  //delete from array
594  $key = array_search($scos[$i], $scos_c);
595  unset($scos_c[$key]);
596  }
597  }
598 
599  //check for completion
600  if(count($scos_c) == 0)
601  {
602  $completion = 1;
603  }
604  else
605  {
606  $completion = 0;
607  }
608 
609  //write export entry
610  if(ilObject::_exists($user) && ilObject::_lookUpType($user) == 'usr')
611  {
612  $e_user = new ilObjUser($user);
613  $login = $e_user->getLogin();
614  $firstname = $e_user->getFirstname();
615  $lastname = $e_user->getLastname();
616  $email = $e_user->getEmail();
617  $department = $e_user->getDepartment();
618 
619  $query = 'SELECT user_id, MAX(c_timestamp) exp_date '
620  . 'FROM cmi_node, cp_node '
621  . 'WHERE cmi_node.cp_node_id = cp_node.cp_node_id '
622  . 'AND cp_node.slm_id = %s '
623  . 'GROUP BY user_id';
624  $res = $ilDB->queryF(
625  $query,
626  array('integer'),
627  array($this->getId())
628  );
629  $data = $ilDB->fetchAssoc($res);
630  if(is_array($data) && count($data))
631  {
632  $validDate = false;
633 
634  $datetime = explode(' ', $data['exp_date']);
635  if(count($datetime) == 2)
636  {
637  $date = explode('-', $datetime[0]);
638  if(count($date) == 3 && checkdate($date[1], $date[2], $date[0]))
639  $validDate = true;
640  }
641 
642  if($validDate)
643  $date = date('d.m.Y', strtotime($data['exp_date']));
644  else
645  $date = '';
646  }
647  else
648  {
649  $date = '';
650  }
651  $csv = $csv. "$department;$login;$lastname;$firstname;$email;$date;$completion\n";
652  }
653  }
654  $header = "Department;Login;Lastname;Firstname;Email;Date;Status\n";
655  $this->sendExportFile($header, $csv);
656  }
657 
658 
659  function importSuccess($a_file) {
660  global $ilDB, $ilUser;
661  $scos = array();
662  //get all SCO's of this object
663  $val_set = $ilDB->queryF('
664  SELECT cp_node.cp_node_id FROM cp_node,cp_resource,cp_item
665  WHERE cp_item.cp_node_id = cp_node.cp_node_id
666  AND cp_item.resourceid = cp_resource.id
667  AND scormtype = %s
668  AND nodename = %s
669  AND cp_node.slm_id = %s
670  GROUP BY cp_node.cp_node_id',
671  array('text','text', 'integer'),
672  array('sco','item', $this->getId())
673  );
674  while ($val_rec = $ilDB->fetchAssoc($val_set))
675  {
676  array_push($scos,$val_rec['cp_node_id']);
677  }
678 
679  $fhandle = fopen($a_file, "r");
680 
681  $obj_id = $this->getID();
682  $users = array();
683 
684  $fields = fgetcsv($fhandle, 4096, ';');
685  while(($csv_rows = fgetcsv($fhandle, 4096, ";")) !== FALSE) {
686  $data = array_combine($fields, $csv_rows);
687  //check the format
688  $statuscheck = 0;
689  if (count($csv_rows) == 6) {$statuscheck = 1;}
690 
691  if ($this->get_user_id($data["Login"])>0) {
692 
693  $user_id = $this->get_user_id($data["Login"]);
694  $import = $data["Status"];
695  if ($import == "") {$import = 1;}
696  //iterate over all SCO's
697  if ($import == 1) {
698  foreach ($scos as $sco)
699  {
700  $sco_id = $sco;
701  $date = $data['Date'];
702 
703  $res = $ilDB->queryF('
704  SELECT * FROM cmi_node
705  WHERE cp_node_id = %s
706  AND user_id = %s
707  AND completion_status = %s
708  AND success_status = %s
709  AND c_timestamp = %s',
710  array('integer','integer','text','text','timestamp'),
711  array($sco_id,$user_id,'completed','passed',$data['Date']));
712 
713  if(!$ilDB->numRows($res))
714  {
715  $nextId = $ilDB->nextId('cmi_node');
716  $val_set = $ilDB->manipulateF('
717  INSERT INTO cmi_node
718  (cp_node_id,user_id,completion_status,success_status,c_timestamp,cmi_node_id)
719  VALUES(%s,%s,%s,%s,%s,%s)',
720  array('integer','integer','text','text','timestamp','integer'),
721  array($sco_id,$user_id,'completed','passed',$data['Date'],$nextId));
722  }
723  }
724 
725  }
726  $users[] = $user_id;
727 
728  } else {
729  //echo "Warning! User $csv_rows[0] does not exist in ILIAS. Data for this user was skipped.\n";
730  }
731  }
732 
733  // update learning progress
734  foreach ($users as $user_id)
735  {
736  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
737  ilLPStatusWrapper::_updateStatus($this->getId(), $user_id);
738  }
739 
740  return 0;
741  }
742 
749  function _ISODurationToCentisec($str) {
750  $aV = array(0, 0, 0, 0, 0, 0);
751  $bErr = false;
752  $bTFound = false;
753  if (strpos($str,"P") != 0) {
754  $bErr = true;
755  }
756  if (!$bErr) {
757  $aT = array("Y", "M", "D", "H", "M", "S");
758  $p = 0;
759  $i = 0;
760  $str = substr($str,1);
761  for ($i = 0; $i < count($aT); $i++) {
762  if (strpos($str,"T")===0) {
763  $str = substr($str,1);
764  $i = max($i, 3);
765  $bTFound = true;
766  }
767  $p = strpos($str,$aT[$i]);
768 
769  if ($p > -1) {
770  if ($i == 1 && strpos($str,"T") > -1 && strpos($str,"T") < $p) {
771  continue;
772  }
773  if ($aT[$i] == "S") {
774  $aV[$i] = substr($str,0, $p);
775 
776  } else {
777  $aV[$i] = intval(substr($str,0, $p));
778  }
779  if (!is_numeric($aV[$i])) {
780  $bErr = true;
781  break;
782  } else if ($i > 2 && !$bTFound) {
783  $bErr = true;
784  break;
785  }
786  $str = substr($str,$p + 1);
787 
788  }
789  }
790  if (!$bErr && strlen($str) != 0) {
791  $bErr = true;
792 
793  }
794  }
795 
796  if ($bErr) {
797  return;
798  }
799  return $aV[0] * 3155760000 + $aV[1] * 262980000 + $aV[2] * 8640000 + $aV[3] * 360000 + $aV[4] * 6000 + round($aV[5] * 100);
800  }
801 
802  function getCourseCompletionForUser($a_user)
803  {
804  global $ilDB, $ilUser;
805 
806  $scos = array();
807  //get all SCO's of this object
808 
809  $val_set = $ilDB->queryF('
810  SELECT cp_node.cp_node_id FROM cp_node,cp_resource,cp_item
811  WHERE cp_item.cp_node_id = cp_node.cp_node_id
812  AND cp_item.resourceid = cp_resource.id
813  AND scormtype = %s
814  AND nodename = %s
815  AND cp_node.slm_id = %s ',
816  array('text','text','integer'),
817  array('sco','item',$this->getId()));
818 
819  while ($val_rec = $ilDB->fetchAssoc($val_set))
820  {
821  array_push($scos,$val_rec['cp_node_id']);
822  }
823 
824 
825  $scos_c = $scos;
826  //copy SCO_array
827  //check if all SCO's are completed
828  for ($i=0;$i<count($scos);$i++)
829  {
830 
831  $val_set = $ilDB->queryF('
832  SELECT * FROM cmi_node
833  WHERE (user_id= %s
834  AND cp_node_id= %s
835  AND (completion_status=%s OR success_status=%s))',
836  array('integer','integer','text', 'text'),
837  array($a_user,$scos[$i],'completed','passed')
838  );
839 
840  if ($ilDB->numRows($val_set) > 0) {
841  //delete from array
842  $key = array_search($scos[$i], $scos_c);
843  unset ($scos_c[$key]);
844  }
845 
846  }
847  //check for completion
848  if (count($scos_c) == 0) {
849  $completion = true;
850  } else {
851  $completion = false;
852  }
853  return $completion;
854  }
855 
862  public static function _getCourseCompletionForUser($a_id, $a_user)
863  {
864  global $ilDB, $ilUser;
865  $scos = array();
866  //get all SCO's of the object
867 
868  $val_set = $ilDB->queryF('
869  SELECT cp_node.cp_node_id FROM cp_node,cp_resource,cp_item
870  WHERE cp_item.cp_node_id = cp_node.cp_node_id
871  AND cp_item.resourceid = cp_resource.id
872  AND scormtype = %s
873  AND nodename = %s
874  AND cp_node.slm_id = %s',
875  array('text','text','integer'), array('sco' ,'item',$a_id));
876  while ($val_rec = $ilDB->fetchAssoc($val_set))
877  {
878  array_push($scos,$val_rec['cp_node_id']);
879  }
880 
881  $scos_c = $scos;
882  //copy SCO_array
883  //check if all SCO's are completed
884  for ($i=0;$i<count($scos);$i++)
885  {
886 
887  $val_set = $ilDB->queryF('
888  SELECT * FROM cmi_node
889  WHERE (user_id= %s
890  AND cp_node_id= %s
891  AND (completion_status = %s OR success_status = %s))',
892  array('integer','integer','text','text'),
893  array($a_user,$scos[$i],'completed','passed'));
894 
895  if ($ilDB->numRows($val_set) > 0)
896  {
897  //delete from array
898  $key = array_search($scos[$i], $scos_c);
899  unset ($scos_c[$key]);
900  }
901 
902  }
903  //check for completion
904  if (count($scos_c) == 0) {
905  $completion = true;
906  } else {
907  $completion = false;
908  }
909  return $completion;
910  }
911 
919  public static function _getUniqueScaledScoreForUser($a_id, $a_user)
920  {
921  global $ilDB, $ilUser;
922  $scos = array();
923 
924  $val_set = $ilDB->queryF("SELECT cp_node.cp_node_id FROM cp_node,cp_resource,cp_item WHERE".
925  " cp_item.cp_node_id=cp_node.cp_node_id AND cp_item.resourceId = cp_resource.id AND scormType='sco' AND nodeName='item' AND cp_node.slm_id = %s GROUP BY cp_node.cp_node_id",
926  array('integer'),
927  array($a_id)
928  );
929  while ($val_rec = $ilDB->fetchAssoc($val_set))
930  {
931  array_push($scos,$val_rec['cp_node_id']);
932  }
933  $set = 0; //numbers of SCO that set cmi.score.scaled
934  $scaled = null;
935  for ($i=0;$i<count($scos);$i++)
936  {
937  $val_set = $ilDB->queryF("SELECT scaled FROM cmi_node WHERE (user_id = %s AND cp_node_id = %s)",
938  array('integer', 'integer'),
939  array($a_user, $scos[$i])
940  );
941  if ($val_set->numRows()>0)
942  {
943  $val_rec = $ilDB->fetchAssoc($val_set);
944  if ($val_rec['scaled']!=NULL) {
945  $set++;
946  $scaled = $val_rec['scaled'];
947  }
948  }
949  }
950  $retVal = ($set == 1) ? $scaled : null ;
951  return $retVal;
952  }
953 
962  function _getTrackingItems($a_obj_id)
963  {
964  global $ilDB;
965 
966 
967  $item_set = $ilDB->queryF('
968  SELECT cp_item.* FROM cp_node, cp_item WHERE slm_id = %s
969  AND cp_node.cp_node_id = cp_item.cp_node_id
970  ORDER BY cp_node.cp_node_id ',
971  array('integer'),
972  array($a_obj_id)
973  );
974 
975  $items = array();
976  while ($item_rec = $ilDB->fetchAssoc($item_set))
977  {
978 
979  $s2 = $ilDB->queryF('
980  SELECT cp_resource.* FROM cp_node, cp_resource
981  WHERE slm_id = %s
982  AND cp_node.cp_node_id = cp_resource.cp_node_id
983  AND cp_resource.id = %s ',
984  array('integer','text'),
985  array($a_obj_id,$item_rec["resourceid"])
986  );
987 
988 
989  if ($res = $ilDB->fetchAssoc($s2))
990 
991  {
992  if ($res["scormtype"] == "sco")
993  {
994  $items[] = array("id" => $item_rec["cp_node_id"],
995  "title" => $item_rec["title"]);
996  }
997  }
998  }
999 
1000  return $items;
1001  }
1002 
1003  static function _getStatus($a_obj_id, $a_user_id)
1004  {
1005  global $ilDB;
1006 
1007  $status_set = $ilDB->queryF('
1008  SELECT * FROM cmi_gobjective
1009  WHERE scope_id = %s
1010  AND objective_id = %s
1011  AND user_id = %s',
1012  array('integer','text','integer'),
1013  array($a_obj_id,'course_overall_status',$a_user_id)
1014  );
1015 
1016  if ($status_rec = $ilDB->fetchAssoc($status_set))
1017  {
1018  return $status_rec["status"];
1019  }
1020 
1021  return false;
1022  }
1023 
1024  static function _getSatisfied($a_obj_id, $a_user_id)
1025  {
1026  global $ilDB;
1027 
1028 
1029  $status_set = $ilDB->queryF('
1030  SELECT * FROM cmi_gobjective
1031  WHERE scope_id = %s
1032  AND objective_id = %s
1033  AND user_id = %s',
1034  array('integer','text','integer'),
1035  array($a_obj_id,'course_overall_status',$a_user_id)
1036  );
1037 
1038  if ($status_rec = $ilDB->fetchAssoc($status_set))
1039  {
1040  return $status_rec["satisfied"];
1041  }
1042 
1043  return false;
1044  }
1045 
1046  static function _getMeasure($a_obj_id, $a_user_id)
1047  {
1048  global $ilDB;
1049 
1050  $status_set = $ilDB->queryF('
1051  SELECT * FROM cmi_gobjective
1052  WHERE scope_id = %s
1053  AND objective_id = %s
1054  AND user_id = %s',
1055  array('integer','text','integer'),
1056  array($a_obj_id,'course_overall_status',$a_user_id)
1057  );
1058 
1059  if ($status_rec = $ilDB->fetchAssoc($status_set))
1060  {
1061  return $status_rec["measure"];
1062  }
1063 
1064  return false;
1065  }
1066 
1067  static function _lookupItemTitle($a_node_id)
1068  {
1069  global $ilDB;
1070 
1071  $r = $ilDB->queryF('
1072  SELECT * FROM cp_item
1073  WHERE cp_node_id = %s',
1074  array('integer'),
1075  array($a_node_id)
1076  );
1077 
1078  if ($i = $ilDB->fetchAssoc($r))
1079  {
1080  return $i["title"];
1081  }
1082  return "";
1083  }
1084 
1089  {
1090  $this->slm_tree =& new ilTree($this->getId());
1091  $this->slm_tree->setTreeTablePK("slm_id");
1092  $this->slm_tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1093  $this->slm_tree->addTree($this->getId(), 1);
1094 
1095  //add seqinfo for rootNode
1096  include_once ("./Modules/Scorm2004/classes/seq_editor/class.ilSCORM2004Sequencing.php");
1097  $seq_info = new ilSCORM2004Sequencing($this->getId(),true);
1098  $seq_info->insert();
1099  }
1100 
1101  function getTree()
1102  {
1103  $this->slm_tree = new ilTree($this->getId());
1104  $this->slm_tree->setTreeTablePK("slm_id");
1105  $this->slm_tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1106  return $this->slm_tree;
1107  }
1108 
1110 
1111  global $ilTabs;
1112  $ilTabs->setTabActive("sequencing");
1113 
1114  include_once ("./Modules/Scorm2004/classes/seq_editor/class.ilSCORM2004Sequencing.php");
1115  $control_settings = new ilSCORM2004Sequencing($this->getId(),true);
1116 
1117  return $control_settings;
1118  }
1119 
1121  include_once ("./Modules/Scorm2004/classes/seq_editor/class.ilSCORM2004Sequencing.php");
1122 
1123  $control_settings = new ilSCORM2004Sequencing($this->getId(),true);
1124  $control_settings->setChoice(ilUtil::yn2tf($_POST["choice"]));
1125  $control_settings->setFlow(ilUtil::yn2tf($_POST["flow"]));
1126  $control_settings->setForwardOnly(ilUtil::yn2tf($_POST["forwardonly"]));
1127  $control_settings->insert();
1128 
1129  return true;
1130  }
1131 
1140  function executeDragDrop($source_id, $target_id, $first_child, $as_subitem = false, $movecopy = "move")
1141  {
1142  $this->slm_tree = new ilTree($this->getId());
1143  $this->slm_tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1144  $this->slm_tree->setTreeTablePK("slm_id");
1145 
1146  require_once("./Modules/Scorm2004/classes/class.ilSCORM2004NodeFactory.php");
1147 
1148  $source_obj = ilSCORM2004NodeFactory::getInstance($this, $source_id, true);
1149  //$source_obj->setLMId($this->getId());
1150 
1151  if (!$first_child)
1152  {
1153  $target_obj = ilSCORM2004NodeFactory::getInstance($this, $target_id, true);
1154  //$target_obj->setLMId($this->getId());
1155  $target_parent = $this->slm_tree->getParentId($target_id);
1156  }
1157 //echo "-".$source_obj->getType()."-";
1158  // handle pages
1159  if ($source_obj->getType() == "page")
1160  {
1161  if ($this->slm_tree->isInTree($source_obj->getId()))
1162  {
1163  $node_data = $this->slm_tree->getNodeData($source_obj->getId());
1164 
1165  // cut on move
1166  if ($movecopy == "move")
1167  {
1168  $parent_id = $this->slm_tree->getParentId($source_obj->getId());
1169  $this->slm_tree->deleteTree($node_data);
1170 
1171  // write history entry
1172 /* require_once("classes/class.ilHistory.php");
1173  ilHistory::_createEntry($source_obj->getId(), "cut",
1174  array(ilLMObject::_lookupTitle($parent_id), $parent_id),
1175  $this->getType().":pg");
1176  ilHistory::_createEntry($parent_id, "cut_page",
1177  array(ilLMObject::_lookupTitle($source_obj->getId()), $source_obj->getId()),
1178  $this->getType().":st");
1179 */
1180  }
1181 /* else // this is not implemented here
1182  {
1183  // copy page
1184  $new_page =& $source_obj->copy();
1185  $source_id = $new_page->getId();
1186  $source_obj =& $new_page;
1187  }
1188 */
1189 
1190  // paste page
1191  if(!$this->slm_tree->isInTree($source_obj->getId()))
1192  {
1193  if ($first_child) // as first child
1194  {
1195  $target_pos = IL_FIRST_NODE;
1196  $parent = $target_id;
1197  }
1198  else if ($as_subitem) // as last child
1199  {
1200  $parent = $target_id;
1201  $target_pos = IL_FIRST_NODE;
1202  $pg_childs = $this->slm_tree->getChildsByType($parent, "page");
1203  if (count($pg_childs) != 0)
1204  {
1205  $target_pos = $pg_childs[count($pg_childs) - 1]["obj_id"];
1206  }
1207  }
1208  else // at position
1209  {
1210  $target_pos = $target_id;
1211  $parent = $target_parent;
1212  }
1213 
1214  // insert page into tree
1215  $this->slm_tree->insertNode($source_obj->getId(),
1216  $parent, $target_pos);
1217 
1218  // write history entry
1219 /* if ($movecopy == "move")
1220  {
1221  // write history comments
1222  include_once("classes/class.ilHistory.php");
1223  ilHistory::_createEntry($source_obj->getId(), "paste",
1224  array(ilLMObject::_lookupTitle($parent), $parent),
1225  $this->getType().":pg");
1226  ilHistory::_createEntry($parent, "paste_page",
1227  array(ilLMObject::_lookupTitle($source_obj->getId()), $source_obj->getId()),
1228  $this->getType().":st");
1229  }
1230 */
1231 
1232  }
1233  }
1234  }
1235 
1236  // handle scos
1237  if ($source_obj->getType() == "sco")
1238  {
1239 //echo "2";
1240  $source_node = $this->slm_tree->getNodeData($source_id);
1241  $subnodes = $this->slm_tree->getSubtree($source_node);
1242 
1243  // check, if target is within subtree
1244  foreach ($subnodes as $subnode)
1245  {
1246  if($subnode["obj_id"] == $target_id)
1247  {
1248  return;
1249  }
1250  }
1251 
1252  $target_pos = $target_id;
1253 
1254  if ($first_child) // as first sco
1255  {
1256  $target_pos = IL_FIRST_NODE;
1257  $target_parent = $target_id;
1258 
1259  $pg_childs = $this->slm_tree->getChildsByType($target_parent, "page");
1260  if (count($pg_childs) != 0)
1261  {
1262  $target_pos = $pg_childs[count($pg_childs) - 1]["obj_id"];
1263  }
1264  }
1265  else if ($as_subitem) // as last sco
1266  {
1267  $target_parent = $target_id;
1268  $target_pos = IL_FIRST_NODE;
1269  $childs = $this->slm_tree->getChilds($target_parent);
1270  if (count($childs) != 0)
1271  {
1272  $target_pos = $childs[count($childs) - 1]["obj_id"];
1273  }
1274  }
1275 
1276  // delete source tree
1277  if ($movecopy == "move")
1278  {
1279  $this->slm_tree->deleteTree($source_node);
1280  }
1281 /* else
1282  {
1283  // copy chapter (incl. subcontents)
1284  $new_chapter =& $source_obj->copy($this->slm_tree, $target_parent, $target_pos);
1285  }
1286 */
1287 
1288  if (!$this->slm_tree->isInTree($source_id))
1289  {
1290  $this->slm_tree->insertNode($source_id, $target_parent, $target_pos);
1291 
1292  // insert moved tree
1293  if ($movecopy == "move")
1294  {
1295  foreach ($subnodes as $node)
1296  {
1297  if($node["obj_id"] != $source_id)
1298  {
1299  $this->slm_tree->insertNode($node["obj_id"], $node["parent"]);
1300  }
1301  }
1302  }
1303  }
1304 
1305  // check the tree
1306 // $this->checkTree();
1307  }
1308 
1309  // handle chapters
1310  if ($source_obj->getType() == "chap")
1311  {
1312 //echo "2";
1313  $source_node = $this->slm_tree->getNodeData($source_id);
1314  $subnodes = $this->slm_tree->getSubtree($source_node);
1315 
1316  // check, if target is within subtree
1317  foreach ($subnodes as $subnode)
1318  {
1319  if($subnode["obj_id"] == $target_id)
1320  {
1321  return;
1322  }
1323  }
1324 
1325  $target_pos = $target_id;
1326 
1327  if ($first_child) // as first chapter
1328  {
1329  $target_pos = IL_FIRST_NODE;
1330  $target_parent = $target_id;
1331 
1332  $sco_childs = $this->slm_tree->getChildsByType($target_parent, "sco");
1333  if (count($sco_childs) != 0)
1334  {
1335  $target_pos = $sco_childs[count($sco_childs) - 1]["obj_id"];
1336  }
1337  }
1338  else if ($as_subitem) // as last chapter
1339  {
1340  $target_parent = $target_id;
1341  $target_pos = IL_FIRST_NODE;
1342  $childs = $this->slm_tree->getChilds($target_parent);
1343  if (count($childs) != 0)
1344  {
1345  $target_pos = $childs[count($childs) - 1]["obj_id"];
1346  }
1347  }
1348 
1349  // delete source tree
1350  if ($movecopy == "move")
1351  {
1352  $this->slm_tree->deleteTree($source_node);
1353  }
1354 /* else
1355  {
1356  // copy chapter (incl. subcontents)
1357  $new_chapter =& $source_obj->copy($this->slm_tree, $target_parent, $target_pos);
1358  }
1359 */
1360 
1361  if (!$this->slm_tree->isInTree($source_id))
1362  {
1363  $this->slm_tree->insertNode($source_id, $target_parent, $target_pos);
1364 
1365  // insert moved tree
1366  if ($movecopy == "move")
1367  {
1368  foreach ($subnodes as $node)
1369  {
1370  if($node["obj_id"] != $source_id)
1371  {
1372  $this->slm_tree->insertNode($node["obj_id"], $node["parent"]);
1373  }
1374  }
1375  }
1376  }
1377 
1378  // check the tree
1379 // $this->checkTree();
1380  }
1381 
1382 // $this->checkTree();
1383  }
1384 
1385  function getExportFiles()
1386  {
1387  $file = array();
1388 
1389  require_once("./Modules/Scorm2004/classes/class.ilSCORM2004Export.php");
1390 
1391  $export = new ilSCORM2004Export($this);
1392  foreach ($export->getSupportedExportTypes() as $type)
1393  {
1394  $dir = $export->getExportDirectoryForType($type);
1395  // quit if import dir not available
1396  if (!@is_dir($dir) or !is_writeable($dir))
1397  {
1398  continue;
1399  }
1400  // open directory
1401  $cdir = dir($dir);
1402 
1403  // get files and save the in the array
1404  while ($entry = $cdir->read())
1405  {
1406  if ($entry != "." and
1407  $entry != ".." and
1408  (
1409  ereg("^[0-9]{10}_{2}[0-9]+_{2}(".$this->getType()."_)*[0-9]+\.zip\$", $entry) or
1410  ereg("^[0-9]{10}_{2}[0-9]+_{2}(".$this->getType()."_)*[0-9]+\.pdf\$", $entry) or
1411  ereg("^[0-9]{10}_{2}[0-9]+_{2}(".$this->getType()."_)*[0-9]+\.iso\$", $entry)
1412  ))
1413  {
1414  $file[$entry.$type] = array("type" => $type, "file" => $entry,
1415  "size" => filesize($dir."/".$entry));
1416  }
1417  }
1418 
1419  // close import directory
1420  $cdir->close();
1421  }
1422 
1423  // sort files
1424  ksort ($file);
1425  reset ($file);
1426  return $file;
1427  }
1428 
1429  function exportScorm($a_inst, $a_target_dir, $ver, &$expLog)
1430  {
1431 
1432  $a_xml_writer = new ilXmlWriter;
1433 
1434  $this->exportXMLMetaData($a_xml_writer);
1435  $metadata_xml = $a_xml_writer->xmlDumpMem(false);
1436  $a_xml_writer->_XmlWriter;
1437 
1438  $xsl = file_get_contents("./Modules/Scorm2004/templates/xsl/metadata.xsl");
1439  $args = array( '/_xml' => $metadata_xml , '/_xsl' => $xsl );
1440  $xh = xslt_create();
1441  $output = xslt_process($xh,"arg:/_xml","arg:/_xsl",NULL,$args,NULL);
1442  xslt_free($xh);
1443  file_put_contents($a_target_dir.'/indexMD.xml',$output);
1444  if($this->getAssignedGlossary()!=0)
1445  {
1446  ilUtil::makeDir($a_target_dir."/glossary");
1447  include_once("./Modules/Glossary/classes/class.ilObjGlossary.php");
1448  include_once("./Modules/Glossary/classes/class.ilGlossaryExport.php");
1449  $glo_xml_writer = new ilXmlWriter();
1450 
1451  $glo_xml_writer->xmlSetDtdDef("<!DOCTYPE ContentObject SYSTEM \"http://www.ilias.de/download/dtd/ilias_co_3_7.dtd\">");
1452  // set xml header
1453  $glo_xml_writer->xmlHeader();
1454  $glos = new ilObjGlossary($this->getAssignedGlossary(), false);
1455  //$glos->exportHTML($a_target_dir."/glossary", $expLog);
1456  $glos_export = new ilGlossaryExport($glos,"xml");
1457  $glos->exportXML($glo_xml_writer,$glos_export->getInstId(), $a_target_dir."/glossary", $expLog);
1458  $glo_xml_writer->xmlDumpFile($a_target_dir."/glossary/glossary.xml");
1459  $glo_xml_writer->_XmlWriter;
1460  }
1461 
1462  $a_xml_writer = new ilXmlWriter;
1463  // set dtd definition
1464  $a_xml_writer->xmlSetDtdDef("<!DOCTYPE ContentObject SYSTEM \"http://www.ilias.de/download/dtd/ilias_co_3_7.dtd\">");
1465 
1466  // set generated comment
1467  $a_xml_writer->xmlSetGenCmt("Export of ILIAS Content Module ". $this->getId()." of installation ".$a_inst.".");
1468 
1469  // set xml header
1470  $a_xml_writer->xmlHeader();
1471 
1472  global $ilBench;
1473 
1474  $a_xml_writer->xmlStartTag("ContentObject", array("Type"=>"SCORM2004LearningModule"));
1475 
1476  // MetaData
1477  $this->exportXMLMetaData($a_xml_writer);
1478 
1479  $this->exportXMLStructureObjects($a_xml_writer, $a_inst, $expLog);
1480 
1481  // SCO Objects
1482  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Sco Objects");
1483  $ilBench->start("ContentObjectExport", "exportScoObjects");
1484  $this->exportXMLScoObjects($a_inst, $a_target_dir, $ver, $expLog);
1485  $ilBench->stop("ContentObjectExport", "exportScoObjects");
1486  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Sco Objects");
1487 
1488  $a_xml_writer->xmlEndTag("ContentObject");
1489  $a_xml_writer->xmlDumpFile($a_target_dir.'/index.xml', false);
1490 
1491  if ($ver == "2004 4th") {
1492  $revision ="4th";
1493  $ver = "2004";
1494  }
1495 
1496  if ($ver == "2004 3rd") {
1497  $revision ="3rd";
1498  $ver = "2004";
1499  }
1500 
1501  include_once("class.ilContObjectManifestBuilder.php");
1502  $manifestBuilder = new ilContObjectManifestBuilder($this);
1503  $manifestBuilder->buildManifest($ver,$revision);
1504  $manifestBuilder->dump($a_target_dir);
1505 
1506  $xsl = file_get_contents("./Modules/Scorm2004/templates/xsl/module.xsl");
1507  $args = array( '/_xml' => file_get_contents($a_target_dir."/imsmanifest.xml"), '/_xsl' => $xsl );
1508  $xh = xslt_create();
1509  $output = xslt_process($xh,"arg:/_xml","arg:/_xsl",NULL,$args,NULL);
1510  xslt_free($xh);
1511  fputs(fopen($a_target_dir.'/index.html','w+'),$output);
1512 
1513  switch ($ver)
1514  {
1515  case "2004":
1516  if ($revision == "3rd") {
1517  ilUtil::rCopy('./Modules/Scorm2004/templates/xsd/adlcp_130_export_2004',$a_target_dir,false);
1518  }
1519 
1520  if ($revision == "4th") {
1521  ilUtil::rCopy('./Modules/Scorm2004/templates/xsd/adlcp_130_export_2004_4th',$a_target_dir,false);
1522  }
1523  break;
1524  case "12":
1525  ilUtil::rCopy('./Modules/Scorm2004/templates/xsd/adlcp_120_export_12',$a_target_dir,false);
1526  break;
1527  }
1528 
1529 
1530  $a_xml_writer->_XmlWriter;
1531  }
1532 
1533 
1534  function exportHTML4PDF($a_inst, $a_target_dir, &$expLog)
1535  {
1536  global $ilBench;
1537  $tree = new ilTree($this->getId());
1538  $tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1539  $tree->setTreeTablePK("slm_id");
1540  foreach($tree->getSubTree($tree->getNodeData($tree->getRootId()),true,'sco') as $sco)
1541  {
1542  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Sco.php");
1543  $sco_folder = $a_target_dir."/".$sco['obj_id'];
1544  ilUtil::makeDir($sco_folder);
1545  $node = new ilSCORM2004Sco($this,$sco['obj_id']);
1546  $node->exportHTML4PDF($a_inst, $sco_folder, $expLog);
1547  }
1548  }
1549 
1550  function exportPDF($a_inst, $a_target_dir, &$expLog)
1551  {
1552  global $ilBench;
1553  $a_xml_writer = new ilXmlWriter;
1554  $a_xml_writer->xmlStartTag("ContentObject", array("Type"=>"SCORM2004SCO"));
1555  $this->exportXMLMetaData($a_xml_writer);
1556  $tree = new ilTree($this->getId());
1557  $tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1558  $tree->setTreeTablePK("slm_id");
1559  foreach($tree->getSubTree($tree->getNodeData($tree->getRootId()),true,'sco') as $sco)
1560  {
1561  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Sco.php");
1562  $sco_folder = $a_target_dir."/".$sco['obj_id'];
1563  ilUtil::makeDir($sco_folder);
1564  $node = new ilSCORM2004Sco($this,$sco['obj_id']);
1565  $node->exportPDFPrepareXmlNFiles($a_inst, $a_target_dir, $expLog, $a_xml_writer);
1566  }
1567  if($this->getAssignedGlossary()!=0)
1568  {
1569  ilUtil::makeDir($a_target_dir."/glossary");
1570  include_once("./Modules/Glossary/classes/class.ilObjGlossary.php");
1571  include_once("./Modules/Glossary/classes/class.ilGlossaryExport.php");
1572  $glos = new ilObjGlossary($this->getAssignedGlossary(), false);
1573  $glos_export = new ilGlossaryExport($glos,"xml");
1574  $glos->exportXML($a_xml_writer,$glos_export->getInstId(), $a_target_dir."/glossary", $expLog);
1575  }
1576  copy('./templates/default/images/icon_attachment_s.png',$a_target_dir."/icon_attachment_s.png");
1577  $a_xml_writer->xmlEndTag("ContentObject");
1578  include_once 'Services/Transformation/classes/class.ilXML2FO.php';
1579  $xml2FO = new ilXML2FO();
1580  $xml2FO->setXSLTLocation('./Modules/Scorm2004/templates/xsl/contentobject2fo.xsl');
1581  $xml2FO->setXMLString($a_xml_writer->xmlDumpMem());
1582  $xml2FO->setXSLTParams(array ('target_dir' => $a_target_dir));
1583  $xml2FO->transform();
1584  $fo_string = $xml2FO->getFOString();
1585  $fo_xml = simplexml_load_string($fo_string);
1586  $fo_ext = $fo_xml->xpath("//fo:declarations");
1587  $fo_ext = $fo_ext[0];
1588  $results = array();
1589  include_once "./Services/Utilities/classes/class.ilFileUtils.php";
1590  ilFileUtils::recursive_dirscan($a_target_dir."/objects", $results);
1591  if (is_array($results["file"]))
1592  {
1593  foreach ($results["file"] as $key => $value)
1594  {
1595  $e = $fo_ext->addChild("fox:embedded-file","","http://xml.apache.org/fop/extensions");
1596  $e->addAttribute("src",$results[path][$key].$value);
1597  $e->addAttribute("name",$value);
1598  $e->addAttribute("desc","");
1599  }
1600  }
1601  $fo_string = $fo_xml->asXML();
1602  $a_xml_writer->_XmlWriter;
1603  return $fo_string;
1604  }
1605 
1606  function exportHTML($a_inst, $a_target_dir, &$expLog)
1607  {
1608  $a_xml_writer = new ilXmlWriter;
1609  // set dtd definition
1610  $a_xml_writer->xmlSetDtdDef("<!DOCTYPE ContentObject SYSTEM \"http://www.ilias.de/download/dtd/ilias_co_3_7.dtd\">");
1611 
1612  // set generated comment
1613  $a_xml_writer->xmlSetGenCmt("Export of ILIAS Content Module ". $this->getId()." of installation ".$a_inst.".");
1614 
1615  // set xml header
1616  $a_xml_writer->xmlHeader();
1617 
1618  global $ilBench;
1619 
1620  $a_xml_writer->xmlStartTag("ContentObject", array("Type"=>"SCORM2004LearningModule"));
1621 
1622  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Sco Objects");
1623  $ilBench->start("ContentObjectExport", "exportScoObjects");
1624  $this->exportHTMLScoObjects($a_inst, $a_target_dir, $expLog);
1625  $ilBench->stop("ContentObjectExport", "exportScoObjects");
1626  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Sco Objects");
1627 
1628  $a_xml_writer->xmlEndTag("ContentObject");
1629 
1630  include_once("class.ilContObjectManifestBuilder.php");
1631  $manifestBuilder = new ilContObjectManifestBuilder($this);
1632  $manifestBuilder->buildManifest('12');
1633 
1634  $xsl = file_get_contents("./Modules/Scorm2004/templates/xsl/module.xsl");
1635  $xml = simplexml_load_string($manifestBuilder->writer->xmlDumpMem());
1636  $args = array( '/_xml' => $xml->organizations->organization->asXml(), '/_xsl' => $xsl );
1637  $xh = xslt_create();
1638  $output = xslt_process($xh,"arg:/_xml","arg:/_xsl",NULL,$args,NULL);
1639  xslt_free($xh);
1640  fputs(fopen($a_target_dir.'/index.html','w+'),$output);
1641  $a_xml_writer->_XmlWriter;
1642  }
1643 
1650  function exportXMLMetaData(&$a_xml_writer)
1651  {
1652  include_once("Services/MetaData/classes/class.ilMD2XML.php");
1653  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
1654  $md2xml->setExportMode(true);
1655  $md2xml->startExport();
1656  $a_xml_writer->appendXML($md2xml->getXML());
1657  }
1658 
1665  function exportXMLStructureObjects(&$a_xml_writer, $a_inst, &$expLog)
1666  {
1667  include_once("Services/MetaData/classes/class.ilMD2XML.php");
1668  $tree = new ilTree($this->getId());
1669  $tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1670  $tree->setTreeTablePK("slm_id");
1671  $a_xml_writer->xmlStartTag("StructureObject");
1672  foreach($tree->getFilteredSubTree($tree->getRootId(),Array('page')) as $obj)
1673  {
1674  if($obj['type']=='') continue;
1675 
1676  //$md2xml = new ilMD2XML($obj['obj_id'], 0, $obj['type']);
1677  $md2xml = new ilMD2XML($this->getId(), $obj['obj_id'], $obj['type']);
1678  $md2xml->setExportMode(true);
1679  $md2xml->startExport();
1680  $a_xml_writer->appendXML($md2xml->getXML());
1681  }
1682  $a_xml_writer->xmlEndTag("StructureObject");
1683  }
1684 
1685 
1692  function exportXMLScoObjects($a_inst, $a_target_dir, $ver, &$expLog)
1693  {
1694  global $ilBench;
1695  $tree = new ilTree($this->getId());
1696  $tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1697  $tree->setTreeTablePK("slm_id");
1698  foreach($tree->getSubTree($tree->getNodeData($tree->getRootId()),true,'sco') as $sco)
1699  {
1700  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Sco.php");
1701  $sco_folder = $a_target_dir."/".$sco['obj_id'];
1702  ilUtil::makeDir($sco_folder);
1703  $node = new ilSCORM2004Sco($this,$sco['obj_id']);
1704  $node->exportScorm($a_inst, $sco_folder, $ver, $expLog);
1705  }
1706  }
1707 
1708  /* export page objects to xml (see ilias_co.dtd)
1709  *
1710  * @param object $a_xml_writer ilXmlWriter object that receives the
1711  * xml data
1712  */
1713  function exportHTMLScoObjects($a_inst, $a_target_dir, &$expLog)
1714  {
1715  global $ilBench;
1716  $tree = new ilTree($this->getId());
1717  $tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1718  $tree->setTreeTablePK("slm_id");
1719  foreach($tree->getSubTree($tree->getNodeData($tree->getRootId()),true,'sco') as $sco)
1720  {
1721  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Sco.php");
1722  $sco_folder = $a_target_dir."/".$sco['obj_id'];
1723  ilUtil::makeDir($sco_folder);
1724  $node = new ilSCORM2004Sco($this,$sco['obj_id']);
1725  $node->exportHTML($a_inst, $sco_folder, $expLog);
1726  if($this->getAssignedGlossary()!=0)
1727  {
1728  include_once("./Modules/Glossary/classes/class.ilObjGlossary.php");
1729  $glos = new ilObjGlossary($this->getAssignedGlossary(),false);
1730  //$glos->exportHTML($sco_folder."/glossary", $expLog);
1731  }
1732  }
1733  }
1734  /* get public export file
1735  *
1736  * @param string $a_type type ("xml" / "html")
1737  *
1738  * @return string $a_file file name
1739  */
1740  function getPublicExportFile($a_type)
1741  {
1742  return $this->public_export_file[$a_type];
1743  }
1744 
1749  function exportFileItems($a_target_dir, &$expLog)
1750  {
1751  include_once("./Modules/File/classes/class.ilObjFile.php");
1752 
1753  foreach ($this->file_ids as $file_id)
1754  {
1755  $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
1756  $file_obj = new ilObjFile($file_id, false);
1757  $file_obj->export($a_target_dir);
1758  unset($file_obj);
1759  }
1760  }
1761 
1762  function setPublicExportFile($a_type, $a_file)
1763  {
1764  $this->public_export_file[$a_type] = $a_file;
1765  }
1766 
1767 } // END class.ilObjSCORM2004LearningModule
1768 ?>