ILIAS  release_4-3 Revision
 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 
41  function setImportSequencing($a_val)
42  {
43  $this->import_sequencing = $a_val;
44  }
45 
52  {
53  return $this->import_sequencing;
54  }
55 
62  function validate($directory)
63  {
64  //$this->validator =& new ilObjSCORMValidator($directory);
65  //$returnValue = $this->validator->validate();
66  return true;
67  }
68 
73  function readObject()
74  {
75  global $ilias, $lng ,$ilDB;
76 
77  //check for MYSQL 4.1 and json_encode,json_decode
78  if (!function_exists('json_encode') || !function_exists('json_decode') || ($ilDB->getDBType() == 'mysql' && !$ilDB->isMysql4_1OrHigher())) {
79  $ilias->raiseError($lng->txt('scplayer_phpmysqlcheck'),$ilias->error_obj->WARNING);
80  }
81 
82  $needs_convert = false;
83 
84  // convert imsmanifest.xml file in iso to utf8 if needed
85 
86  $manifest_file = $this->getDataDirectory()."/imsmanifest.xml";
87 
88  // check if manifestfile exists and space left on device...
89  $check_for_manifest_file = is_file($manifest_file);
90 
91 
92 
93  // if no manifestfile
94  if (!$check_for_manifest_file)
95  {
96  $this->ilias->raiseError($this->lng->txt("Manifestfile $manifest_file not found!"), $this->ilias->error_obj->MESSAGE);
97  return;
98  }
99 
100 
101  if ($check_for_manifest_file)
102  {
103  $manifest_file_array = file($manifest_file);
104 
105  foreach($manifest_file_array as $mfa)
106  {
107  // if (seems_not_utf8($mfa))
108  if (@iconv('UTF-8', 'UTF-8', $mfa) != $mfa)
109  {
110  $needs_convert = true;
111  break;
112  }
113  }
114 
115 
116 
117  // to copy the file we need some extraspace, counted in bytes *2 ... we need 2 copies....
118  $estimated_manifest_filesize = filesize($manifest_file) * 2;
119 
120  // i deactivated this, because it seems to fail on some windows systems (see bug #1795)
121  //$check_disc_free = disk_free_space($this->getDataDirectory()) - $estimated_manifest_filesize;
122  $check_disc_free = 2;
123  }
124 
125 
126  // if $manifest_file needs to be converted to UTF8
127  if ($needs_convert)
128  {
129  // if file exists and enough space left on device
130  if ($check_for_manifest_file && ($check_disc_free > 1))
131  {
132 
133  // create backup from original
134  if (!copy($manifest_file, $manifest_file.".old"))
135  {
136  echo "Failed to copy $manifest_file...<br>\n";
137  }
138 
139  // read backupfile, convert each line to utf8, write line to new file
140  // php < 4.3 style
141  $f_write_handler = fopen($manifest_file.".new", "w");
142  $f_read_handler = fopen($manifest_file.".old", "r");
143  while (!feof($f_read_handler))
144  {
145  $zeile = fgets($f_read_handler);
146  //echo mb_detect_encoding($zeile);
147  fputs($f_write_handler, utf8_encode($zeile));
148  }
149  fclose($f_read_handler);
150  fclose($f_write_handler);
151 
152  // copy new utf8-file to imsmanifest.xml
153  if (!copy($manifest_file.".new", $manifest_file))
154  {
155  echo "Failed to copy $manifest_file...<br>\n";
156  }
157 
158  if (!@is_file($manifest_file))
159  {
160  $this->ilias->raiseError($this->lng->txt("cont_no_manifest"),
161  $this->ilias->error_obj->WARNING);
162  }
163  }
164  else
165  {
166  // gives out the specific error
167 
168  if (!($check_disc_free > 1))
169  $this->ilias->raiseError($this->lng->txt("Not enough space left on device!"),$this->ilias->error_obj->MESSAGE);
170  return;
171  }
172 
173  }
174  else
175  {
176  // check whether file starts with BOM (that confuses some sax parsers, see bug #1795)
177  $hmani = fopen($manifest_file, "r");
178  $start = fread($hmani, 3);
179  if (strtolower(bin2hex($start)) == "efbbbf")
180  {
181  $f_write_handler = fopen($manifest_file.".new", "w");
182  while (!feof($hmani))
183  {
184  $n = fread($hmani, 900);
185  fputs($f_write_handler, $n);
186  }
187  fclose($f_write_handler);
188  fclose($hmani);
189 
190  // copy new utf8-file to imsmanifest.xml
191  if (!copy($manifest_file.".new", $manifest_file))
192  {
193  echo "Failed to copy $manifest_file...<br>\n";
194  }
195  }
196  else
197  {
198  fclose($hmani);
199  }
200  }
201 
202  //validate the XML-Files in the SCORM-Package
203  if ($_POST["validate"] == "y")
204  {
205  if (!$this->validate($this->getDataDirectory()))
206  {
207  $this->ilias->raiseError("<b>Validation Error(s):</b><br>".$this->getValidationSummary(),
208  $this->ilias->error_obj->WARNING);
209  }
210  }
211 
212 
213  //check for SCORM 1.2
214  $this->convert_1_2_to_2004($manifest_file);
215 
216  // start SCORM 2004 package parser/importer
217  include_once ("./Modules/Scorm2004/classes/ilSCORM13Package.php");
218  $newPack = new ilSCORM13Package();
219  if ($this->getEditable())
220  {
221  return $newPack->il_importLM($this,$this->getDataDirectory(),
222  $this->getImportSequencing());
223  }
224  else
225  {
226  return $newPack->il_import($this->getDataDirectory(),$this->getId(),$this->ilias,$_POST["validate"]);
227  }
228  }
229 
230 
231  public function fixReload() {
232  $out = file_get_contents($this->imsmanifestFile);
233  $check ='/xmlns="http:\/\/www.imsglobal.org\/xsd\/imscp_v1p1"/';
234  $replace="xmlns=\"http://www.imsproject.org/xsd/imscp_rootv1p1p2\"";
235  $out=preg_replace($check, $replace, $out);
236  file_put_contents($this->imsmanifestFile, $out);
237  }
238 
239 
240  public function convert_1_2_to_2004($manifest) {
241  global $ilDB, $ilLog;
242 
243  ##check manifest-file for version. Check for schemaversion as this is a required element for SCORM 2004
244  ##accept 2004 3rd Edition an CAM 1.3 as valid schemas
245 
246  //set variables
247  $this->packageFolder=$this->getDataDirectory();
248  $this->imsmanifestFile=$manifest;
249  $doc = new DomDocument();
250 
251  //fix reload errors before loading
252  $this->fixReload();
253  $doc->load($this->imsmanifestFile);
254  $elements = $doc->getElementsByTagName("schemaversion");
255  $schema=$elements->item(0)->nodeValue;
256  if (strtolower(trim($schema))=="cam 1.3" || strtolower(trim($schema))=="2004 3rd edition" || strtolower(trim($schema))=="2004 4th edition") {
257  //no conversion
258  $this->converted=false;
259  return true;
260 
261  } else {
262  $this->converted=true;
263  //convert to SCORM 2004
264 
265  //check for broken SCORM 1.2 manifest file (missing organization default-common error in a lot of manifest files)
266  $organizations = $doc->getElementsByTagName("organizations");
267  $default=$organizations->item(0)->getAttribute("default");
268  if ($default=="" || $default==null) {
269  //lookup identifier
270  $organization = $doc->getElementsByTagName("organization");
271  $ident=$organization->item(0)->getAttribute("identifier");
272  $organizations->item(0)->setAttribute("default",$ident);
273  }
274 
275  //validate the fixed mainfest. If it's still not valid, don't transform an throw error
276 
277 
278  //first copy wrappers
279  $wrapperdir=$this->packageFolder."/GenericRunTimeWrapper1.0_aadlc";
280  mkdir($wrapperdir);
281  copy(self::WRAPPER_HTML,$wrapperdir."/GenericRunTimeWrapper.htm");
282  copy(self::WRAPPER_JS,$wrapperdir."/SCOPlayerWrapper.js");
283 
284  //backup manifestfile
285  $this->backupManifest=$this->packageFolder."/imsmanifest.xml.back";
286  $ret=copy($this->imsmanifestFile,$this->backupManifest);
287 
288  //transform manifest file
289  $this->totransform = $doc;
290  $ilLog->write("SCORM: about to transform to SCORM 2004");
291 
292  $xsl = new DOMDocument;
293  $xsl->async = false;
294  $xsl->load(self::CONVERT_XSL);
295  $prc = new XSLTProcessor;
296  $r = @$prc->importStyleSheet($xsl);
297 
298  file_put_contents($this->imsmanifestFile, $prc->transformToXML($this->totransform));
299 
300  $ilLog->write("SCORM: Transoformation completed");
301  return true;
302  }
303 
304  }
305 
313  public static function _lookupLastAccess($a_obj_id, $a_usr_id)
314  {
315  global $ilDB;
316 
317  $result = $ilDB->queryF('
318  SELECT MAX(c_timestamp) last_access
319  FROM cmi_node, cp_node
320  WHERE cmi_node.cp_node_id = cp_node.cp_node_id
321  AND cp_node.slm_id = %s
322  AND user_id = %s
323  GROUP BY c_timestamp',
324  array('integer', 'integer'),
325  array($a_obj_id, $a_usr_id));
326  if ($ilDB->numRows($result))
327  {
328  $row = $ilDB->fetchAssoc($result);
329  return $row["last_access"];
330  }
331 
332  return "";
333  }
334 
338  function getTrackedUsers($a_search)
339  {
340  global $ilUser, $ilDB, $ilUser;
341 
342  $sco_set = $ilDB->queryF('
343  SELECT DISTINCT user_id,MAX(c_timestamp) last_access
344  FROM cmi_node, cp_node
345  WHERE cmi_node.cp_node_id = cp_node.cp_node_id
346  AND cp_node.slm_id = %s
347  GROUP BY user_id',
348  array('integer'),
349  array($this->getId()));
350 
351  $items = array();
352  $temp = array();
353 
354  while($sco_rec = $ilDB->fetchAssoc($sco_set))
355  {
356  $name = ilObjUser::_lookupName($sco_rec["user_id"]);
357  if ($sco_rec['last_access'] != 0) {
358 // $sco_rec['last_access'] = $sco_rec['last_access'];
359  } else {
360  $sco_rec['last_access'] = "";
361  }
362  if (ilObject::_exists($sco_rec['user_id']) && ilObject::_lookUpType($sco_rec['user_id'])=="usr" ) {
363  $user = new ilObjUser($sco_rec['user_id']);
364  $temp = array("user_full_name" => $name["lastname"].", ".
365  $name["firstname"]." [".ilObjUser::_lookupLogin($sco_rec["user_id"])."]",
366  "user_id" => $sco_rec["user_id"],"last_access" => $sco_rec['last_access'],
367  "version"=> $this->getModuleVersionForUser($sco_rec["user_id"]),
368  "attempts" => $this->getAttemptsForUser($sco_rec["user_id"]),
369  "username" => $user->getLastname().", ".$user->getFirstname()
370  );
371  if ($a_search != "" && (strpos(strtolower($user->getLastname()), strtolower($a_search)) !== false || strpos(strtolower($user->getFirstname()), strtolower($a_search)) !== false ) ) {
372  $items[] = $temp;
373  } else if ($a_search == "") {
374  $items[] = $temp;
375  }
376  }
377  }
378 
379  return $items;
380  }
381 
385  function deleteTrackingDataOfUsers($a_users)
386  {
387  global $ilDB;
388 
389  foreach($a_users as $user)
390  {
391  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004DeleteData.php");
393 
394  // update learning progress
395  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
396  ilLPStatusWrapper::_updateStatus($this->getId(), $user);
397  }
398  }
399 
400 
401  function getTrackedItems()
402  {
403  global $ilUser, $ilDB, $ilUser;
404 
405  $sco_set = $ilDB->queryF('
406  SELECT DISTINCT cmi_node.cp_node_id id
407  FROM cp_node, cmi_node
408  WHERE slm_id = %s
409  AND cp_node.cp_node_id = cmi_node.cp_node_id
410  ORDER BY cp_node.cp_node_id ',
411  array('integer'),
412  array($this->getId()));
413 
414  $items = array();
415 
416  while($sco_rec = $ilDB->fetchAssoc($sco_set))
417  {
418  $item['id']=$sco_rec["id"];
419  $item['title']=self::_lookupItemTitle($sco_rec["id"]);
420  $items[count($items)] =$item;
421 
422  }
423  return $items;
424  }
425 
426 
427  function getTrackingDataAgg($a_user_id, $raw = false)
428  {
429  global $ilDB;
430 
431  $scos = array();
432  $data = array();
433  //get all SCO's of this object
434 
435  $val_set = $ilDB->queryF(
436  'SELECT cp_node_id FROM cp_node
437  WHERE nodename = %s
438  AND cp_node.slm_id = %s',
439  array('text', 'integer'),
440  array('item',$this->getId())
441  );
442  while($val_rec = $ilDB->fetchAssoc($val_set))
443  {
444  array_push($scos,$val_rec['cp_node_id']);
445  }
446 
447  foreach ($scos as $sco)
448  {
449  $data_set = $ilDB->queryF('
450  SELECT c_timestamp last_access, total_time, success_status, completion_status,
451  c_raw, scaled, cp_node_id
452  FROM cmi_node
453  WHERE cp_node_id = %s
454  AND user_id = %s',
455  array('integer','integer'),
456  array($sco,$a_user_id)
457  );
458 
459  while($data_rec = $ilDB->fetchAssoc($data_set))
460  {
461  if ($data_rec["success_status"]!="" && $data_rec["success_status"]!="unknown") {
462  $status = $data_rec["success_status"];
463  } else {
464  if ($data_rec["completion_status"]=="") {
465  $status="unknown";
466  } else {
467  $status = $data_rec["completion_status"];
468  }
469  }
470  if(!$raw)
471  {
472  $time = ilFormat::_secondsToString(self::_ISODurationToCentisec($data_rec["total_time"])/100);
473  $score = "";
474  if ($data_rec["c_raw"] != null) {
475  $score = $data_rec["c_raw"];
476  if ($data_rec["scaled"] != null) $score .= " = ";
477  }
478  if ($data_rec["scaled"] != null) $score .= ($data_rec["scaled"]*100)."%";
479  $title = self::_lookupItemTitle($data_rec["cp_node_id"]);
480  $last_access=ilDatePresentation::formatDate(new ilDateTime($data_rec['last_access'],IL_CAL_UNIX));
481  $data[] = array("user_id" => $data_rec["user_id"], "sco_id"=>$data_rec["cp_node_id"],
482  "score" => $score, "time" => $time, "status" => $status,"last_access"=>$last_access,"title"=>$title);
483  }
484  else
485  {
486  $data_rec["session_time"] = self::_ISODurationToCentisec($data_rec["session_time"])/100;
487  $data[$data_rec["cp_node_id"]] = $data_rec;
488  }
489  }
490  }
491 
492 
493  return $data;
494  }
495 
499  function getAttemptsForUser($a_user_id){
500  global $ilDB;
501 
502  $val_set = $ilDB->queryF('
503  SELECT * FROM cmi_custom
504  WHERE user_id = %s
505  AND sco_id = %s
506  AND lvalue = %s
507  AND obj_id = %s',
508  array('integer','integer', 'text','integer'),
509  array($a_user_id, 0,'package_attempts',$this->getId()));
510 
511  $val_rec = $ilDB->fetchAssoc($val_set);
512 
513  $val_rec["rvalue"] = str_replace("\r\n", "\n", $val_rec["rvalue"]);
514  if ($val_rec["rvalue"] == null) {
515  $val_rec["rvalue"]="";
516  }
517 
518  return $val_rec["rvalue"];
519  }
520 
521 
525  function getModuleVersionForUser($a_user_id){
526  global $ilDB;
527 
528  $val_set = $ilDB->queryF('
529  SELECT * FROM cmi_custom
530  WHERE user_id = %s
531  AND sco_id = %s
532  AND lvalue = %s
533  AND obj_id = %s',
534  array('integer','integer', 'text','integer'),
535  array($a_user_id, 0,'module_version',$this->getId()));
536 
537  $val_rec = $ilDB->fetchAssoc($val_set);
538 
539  $val_rec["rvalue"] = str_replace("\r\n", "\n", $val_rec["rvalue"]);
540  if ($val_rec["rvalue"] == null) {
541  $val_rec["rvalue"]="";
542  }
543  return $val_rec["rvalue"];
544  }
545 
546 
547 
548  function exportSelected($a_exportall = 0, $a_user = array())
549  {
550  global $ilDB, $ilUser;
551 
552  $scos = array();
553 
554  //get all SCO's of this object
555  $query = 'SELECT cp_node.cp_node_id '
556  . 'FROM cp_node, cp_resource, cp_item '
557  . 'WHERE cp_item.cp_node_id = cp_node.cp_node_id '
558  . 'AND cp_item.resourceid = cp_resource.id AND scormtype = %s '
559  . 'AND nodename = %s AND cp_node.slm_id = %s';
560  $res = $ilDB->queryF(
561  $query,
562  array('text', 'text', 'integer'),
563  array('sco', 'item', $this->getId())
564  );
565  while($row = $ilDB->fetchAssoc($res))
566  {
567  $scos[] = $row['cp_node_id'];
568  }
569 
570  $csv = null;
571 
572  //a module is completed when all SCO's are completed
573  $user_array = array();
574 
575  if($a_exportall == 1)
576  {
577  $query = 'SELECT user_id '
578  . 'FROM cmi_node, cp_node '
579  . 'WHERE cmi_node.cp_node_id = cp_node.cp_node_id AND cp_node.slm_id = %s '
580  . 'GROUP BY user_id';
581  $res = $ilDB->queryF(
582  $query,
583  array('integer'),
584  array($this->getId())
585  );
586  while($row = $ilDB->fetchAssoc($res))
587  {
588  $user_array[] = $row['user_id'];
589  }
590  }
591  else
592  {
593  $user_array = $a_user;
594  }
595 
596  foreach($user_array as $user)
597  {
598  $scos_c = $scos;
599  //copy SCO_array
600  //check if all SCO's are completed
601  for($i = 0; $i < count($scos); $i++)
602  {
603  $query = 'SELECT * FROM cmi_node '
604  . 'WHERE user_id = %s AND cp_node_id = %s '
605  . 'AND completion_status = %s OR success_status = %s';
606  $res = $ilDB->queryF(
607  $query,
608  array('integer', 'integer', 'text', 'text'),
609  array($user, $scos[$i], 'completed', 'passed')
610  );
611 
612  $data = $ilDB->fetchAssoc($res);
613  if(is_array($data) && count($data))
614  {
615  //delete from array
616  $key = array_search($scos[$i], $scos_c);
617  unset($scos_c[$key]);
618  }
619  }
620 
621  //check for completion
622  if(count($scos_c) == 0)
623  {
624  $completion = 1;
625  }
626  else
627  {
628  $completion = 0;
629  }
630 
631  //write export entry
632  if(ilObject::_exists($user) && ilObject::_lookUpType($user) == 'usr')
633  {
634  $e_user = new ilObjUser($user);
635  $login = $e_user->getLogin();
636  $firstname = $e_user->getFirstname();
637  $lastname = $e_user->getLastname();
638  $email = $e_user->getEmail();
639  $department = $e_user->getDepartment();
640 
641  $query = 'SELECT user_id, MAX(c_timestamp) exp_date '
642  . 'FROM cmi_node, cp_node '
643  . 'WHERE cmi_node.cp_node_id = cp_node.cp_node_id '
644  . 'AND cp_node.slm_id = %s '
645  . 'GROUP BY user_id';
646  $res = $ilDB->queryF(
647  $query,
648  array('integer'),
649  array($this->getId())
650  );
651  $data = $ilDB->fetchAssoc($res);
652  if(is_array($data) && count($data))
653  {
654  $validDate = false;
655 
656  $datetime = explode(' ', $data['exp_date']);
657  if(count($datetime) == 2)
658  {
659  $date = explode('-', $datetime[0]);
660  if(count($date) == 3 && checkdate($date[1], $date[2], $date[0]))
661  $validDate = true;
662  }
663 
664  if($validDate)
665  $date = date('d.m.Y', strtotime($data['exp_date']));
666  else
667  $date = '';
668  }
669  else
670  {
671  $date = '';
672  }
673  $csv = $csv. "$department;$login;$lastname;$firstname;$email;$date;$completion\n";
674  }
675  }
676  $header = "Department;Login;Lastname;Firstname;Email;Date;Status\n";
677  $this->sendExportFile($header, $csv);
678  }
679 
680 
681  function importSuccess($a_file) {
682  global $ilDB, $ilUser;
683  $scos = array();
684  //get all SCO's of this object
685  $val_set = $ilDB->queryF('
686  SELECT cp_node.cp_node_id FROM cp_node,cp_resource,cp_item
687  WHERE cp_item.cp_node_id = cp_node.cp_node_id
688  AND cp_item.resourceid = cp_resource.id
689  AND scormtype = %s
690  AND nodename = %s
691  AND cp_node.slm_id = %s
692  GROUP BY cp_node.cp_node_id',
693  array('text','text', 'integer'),
694  array('sco','item', $this->getId())
695  );
696  while ($val_rec = $ilDB->fetchAssoc($val_set))
697  {
698  array_push($scos,$val_rec['cp_node_id']);
699  }
700 
701  $fhandle = fopen($a_file, "r");
702 
703  $obj_id = $this->getID();
704  $users = array();
705 
706  $fields = fgetcsv($fhandle, 4096, ';');
707  while(($csv_rows = fgetcsv($fhandle, 4096, ";")) !== FALSE) {
708  $data = array_combine($fields, $csv_rows);
709  //check the format
710  $statuscheck = 0;
711  if (count($csv_rows) == 6) {$statuscheck = 1;}
712 
713  if ($this->get_user_id($data["Login"])>0) {
714 
715  $user_id = $this->get_user_id($data["Login"]);
716  $import = $data["Status"];
717  if ($import == "") {$import = 1;}
718  //iterate over all SCO's
719  if ($import == 1) {
720  foreach ($scos as $sco)
721  {
722  $sco_id = $sco;
723  $date = $data['Date'];
724 
725  $res = $ilDB->queryF('
726  SELECT * FROM cmi_node
727  WHERE cp_node_id = %s
728  AND user_id = %s
729  AND completion_status = %s
730  AND success_status = %s
731  AND c_timestamp = %s',
732  array('integer','integer','text','text','timestamp'),
733  array($sco_id,$user_id,'completed','passed',$data['Date']));
734 
735  if(!$ilDB->numRows($res))
736  {
737  $nextId = $ilDB->nextId('cmi_node');
738  $val_set = $ilDB->manipulateF('
739  INSERT INTO cmi_node
740  (cp_node_id,user_id,completion_status,success_status,c_timestamp,cmi_node_id)
741  VALUES(%s,%s,%s,%s,%s,%s)',
742  array('integer','integer','text','text','timestamp','integer'),
743  array($sco_id,$user_id,'completed','passed',$data['Date'],$nextId));
744  }
745  }
746 
747  }
748  $users[] = $user_id;
749 
750  } else {
751  //echo "Warning! User $csv_rows[0] does not exist in ILIAS. Data for this user was skipped.\n";
752  }
753  }
754 
755  // update learning progress
756  foreach ($users as $user_id)
757  {
758  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
759  ilLPStatusWrapper::_updateStatus($this->getId(), $user_id);
760  }
761 
762  return 0;
763  }
764 
771  function _ISODurationToCentisec($str) {
772  $aV = array(0, 0, 0, 0, 0, 0);
773  $bErr = false;
774  $bTFound = false;
775  if (strpos($str,"P") != 0) {
776  $bErr = true;
777  }
778  if (!$bErr) {
779  $aT = array("Y", "M", "D", "H", "M", "S");
780  $p = 0;
781  $i = 0;
782  $str = substr($str,1);
783  for ($i = 0; $i < count($aT); $i++) {
784  if (strpos($str,"T")===0) {
785  $str = substr($str,1);
786  $i = max($i, 3);
787  $bTFound = true;
788  }
789  $p = strpos($str,$aT[$i]);
790 
791  if ($p > -1) {
792  if ($i == 1 && strpos($str,"T") > -1 && strpos($str,"T") < $p) {
793  continue;
794  }
795  if ($aT[$i] == "S") {
796  $aV[$i] = substr($str,0, $p);
797 
798  } else {
799  $aV[$i] = intval(substr($str,0, $p));
800  }
801  if (!is_numeric($aV[$i])) {
802  $bErr = true;
803  break;
804  } else if ($i > 2 && !$bTFound) {
805  $bErr = true;
806  break;
807  }
808  $str = substr($str,$p + 1);
809 
810  }
811  }
812  if (!$bErr && strlen($str) != 0) {
813  $bErr = true;
814 
815  }
816  }
817 
818  if ($bErr) {
819  return;
820  }
821  return $aV[0] * 3155760000 + $aV[1] * 262980000 + $aV[2] * 8640000 + $aV[3] * 360000 + $aV[4] * 6000 + round($aV[5] * 100);
822  }
823 
824  function getCourseCompletionForUser($a_user)
825  {
826  global $ilDB, $ilUser;
827 
828  $scos = array();
829  //get all SCO's of this object
830 
831  $val_set = $ilDB->queryF('
832  SELECT cp_node.cp_node_id FROM cp_node,cp_resource,cp_item
833  WHERE cp_item.cp_node_id = cp_node.cp_node_id
834  AND cp_item.resourceid = cp_resource.id
835  AND scormtype = %s
836  AND nodename = %s
837  AND cp_node.slm_id = %s ',
838  array('text','text','integer'),
839  array('sco','item',$this->getId()));
840 
841  while ($val_rec = $ilDB->fetchAssoc($val_set))
842  {
843  array_push($scos,$val_rec['cp_node_id']);
844  }
845 
846 
847  $scos_c = $scos;
848  //copy SCO_array
849  //check if all SCO's are completed
850  for ($i=0;$i<count($scos);$i++)
851  {
852 
853  $val_set = $ilDB->queryF('
854  SELECT * FROM cmi_node
855  WHERE (user_id= %s
856  AND cp_node_id= %s
857  AND (completion_status=%s OR success_status=%s))',
858  array('integer','integer','text', 'text'),
859  array($a_user,$scos[$i],'completed','passed')
860  );
861 
862  if ($ilDB->numRows($val_set) > 0) {
863  //delete from array
864  $key = array_search($scos[$i], $scos_c);
865  unset ($scos_c[$key]);
866  }
867 
868  }
869  //check for completion
870  if (count($scos_c) == 0) {
871  $completion = true;
872  } else {
873  $completion = false;
874  }
875  return $completion;
876  }
877 
884  public static function _getCourseCompletionForUser($a_id, $a_user)
885  {
886  global $ilDB, $ilUser;
887  $scos = array();
888  //get all SCO's of the object
889 
890  $val_set = $ilDB->queryF('
891  SELECT cp_node.cp_node_id FROM cp_node,cp_resource,cp_item
892  WHERE cp_item.cp_node_id = cp_node.cp_node_id
893  AND cp_item.resourceid = cp_resource.id
894  AND scormtype = %s
895  AND nodename = %s
896  AND cp_node.slm_id = %s',
897  array('text','text','integer'), array('sco' ,'item',$a_id));
898  while ($val_rec = $ilDB->fetchAssoc($val_set))
899  {
900  array_push($scos,$val_rec['cp_node_id']);
901  }
902 
903  $scos_c = $scos;
904  //copy SCO_array
905  //check if all SCO's are completed
906  for ($i=0;$i<count($scos);$i++)
907  {
908 
909  $val_set = $ilDB->queryF('
910  SELECT * FROM cmi_node
911  WHERE (user_id= %s
912  AND cp_node_id= %s
913  AND (completion_status = %s OR success_status = %s))',
914  array('integer','integer','text','text'),
915  array($a_user,$scos[$i],'completed','passed'));
916 
917  if ($ilDB->numRows($val_set) > 0)
918  {
919  //delete from array
920  $key = array_search($scos[$i], $scos_c);
921  unset ($scos_c[$key]);
922  }
923 
924  }
925  //check for completion
926  if (count($scos_c) == 0) {
927  $completion = true;
928  } else {
929  $completion = false;
930  }
931  return $completion;
932  }
933 
941  public static function _getUniqueScaledScoreForUser($a_id, $a_user)
942  {
943  global $ilDB, $ilUser;
944  $scos = array();
945 
946  $val_set = $ilDB->queryF("SELECT cp_node.cp_node_id FROM cp_node,cp_resource,cp_item WHERE".
947  " 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",
948  array('integer'),
949  array($a_id)
950  );
951  while ($val_rec = $ilDB->fetchAssoc($val_set))
952  {
953  array_push($scos,$val_rec['cp_node_id']);
954  }
955  $set = 0; //numbers of SCO that set cmi.score.scaled
956  $scaled = null;
957  for ($i=0;$i<count($scos);$i++)
958  {
959  $val_set = $ilDB->queryF("SELECT scaled FROM cmi_node WHERE (user_id = %s AND cp_node_id = %s)",
960  array('integer', 'integer'),
961  array($a_user, $scos[$i])
962  );
963  if ($val_set->numRows()>0)
964  {
965  $val_rec = $ilDB->fetchAssoc($val_set);
966  if ($val_rec['scaled']!=NULL) {
967  $set++;
968  $scaled = $val_rec['scaled'];
969  }
970  }
971  }
972  $retVal = ($set == 1) ? $scaled : null ;
973  return $retVal;
974  }
975 
984  function _getTrackingItems($a_obj_id)
985  {
986  global $ilDB;
987 
988 
989  $item_set = $ilDB->queryF('
990  SELECT cp_item.* FROM cp_node, cp_item WHERE slm_id = %s
991  AND cp_node.cp_node_id = cp_item.cp_node_id
992  ORDER BY cp_node.cp_node_id ',
993  array('integer'),
994  array($a_obj_id)
995  );
996 
997  $items = array();
998  while ($item_rec = $ilDB->fetchAssoc($item_set))
999  {
1000 
1001  $s2 = $ilDB->queryF('
1002  SELECT cp_resource.* FROM cp_node, cp_resource
1003  WHERE slm_id = %s
1004  AND cp_node.cp_node_id = cp_resource.cp_node_id
1005  AND cp_resource.id = %s ',
1006  array('integer','text'),
1007  array($a_obj_id,$item_rec["resourceid"])
1008  );
1009 
1010 
1011  if ($res = $ilDB->fetchAssoc($s2))
1012 
1013  {
1014  if ($res["scormtype"] == "sco")
1015  {
1016  $items[] = array("id" => $item_rec["cp_node_id"],
1017  "title" => $item_rec["title"]);
1018  }
1019  }
1020  }
1021 
1022  return $items;
1023  }
1024 
1025  static function _getStatus($a_obj_id, $a_user_id)
1026  {
1027  global $ilDB;
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["status"];
1041  }
1042 
1043  return false;
1044  }
1045 
1046  static function _getSatisfied($a_obj_id, $a_user_id)
1047  {
1048  global $ilDB;
1049 
1050 
1051  $status_set = $ilDB->queryF('
1052  SELECT * FROM cmi_gobjective
1053  WHERE scope_id = %s
1054  AND objective_id = %s
1055  AND user_id = %s',
1056  array('integer','text','integer'),
1057  array($a_obj_id,'course_overall_status',$a_user_id)
1058  );
1059 
1060  if ($status_rec = $ilDB->fetchAssoc($status_set))
1061  {
1062  return $status_rec["satisfied"];
1063  }
1064 
1065  return false;
1066  }
1067 
1068  static function _getMeasure($a_obj_id, $a_user_id)
1069  {
1070  global $ilDB;
1071 
1072  $status_set = $ilDB->queryF('
1073  SELECT * FROM cmi_gobjective
1074  WHERE scope_id = %s
1075  AND objective_id = %s
1076  AND user_id = %s',
1077  array('integer','text','integer'),
1078  array($a_obj_id,'course_overall_status',$a_user_id)
1079  );
1080 
1081  if ($status_rec = $ilDB->fetchAssoc($status_set))
1082  {
1083  return $status_rec["measure"];
1084  }
1085 
1086  return false;
1087  }
1088 
1089  static function _lookupItemTitle($a_node_id)
1090  {
1091  global $ilDB;
1092 
1093  $r = $ilDB->queryF('
1094  SELECT * FROM cp_item
1095  WHERE cp_node_id = %s',
1096  array('integer'),
1097  array($a_node_id)
1098  );
1099 
1100  if ($i = $ilDB->fetchAssoc($r))
1101  {
1102  return $i["title"];
1103  }
1104  return "";
1105  }
1106 
1111  {
1112  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Tree.php");
1113  $this->slm_tree = new ilSCORM2004Tree($this->getId());
1114 
1115  //$this->slm_tree =& new ilTree($this->getId());
1116  //$this->slm_tree->setTreeTablePK("slm_id");
1117  //$this->slm_tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1118  $this->slm_tree->addTree($this->getId(), 1);
1119 
1120  //add seqinfo for rootNode
1121  include_once ("./Modules/Scorm2004/classes/seq_editor/class.ilSCORM2004Sequencing.php");
1122  $seq_info = new ilSCORM2004Sequencing($this->getId(),true);
1123  $seq_info->insert();
1124  }
1125 
1126  function getTree()
1127  {
1128  $this->slm_tree = new ilTree($this->getId());
1129  $this->slm_tree->setTreeTablePK("slm_id");
1130  $this->slm_tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1131  return $this->slm_tree;
1132  }
1133 
1135 
1136  global $ilTabs;
1137  $ilTabs->setTabActive("sequencing");
1138 
1139  include_once ("./Modules/Scorm2004/classes/seq_editor/class.ilSCORM2004Sequencing.php");
1140  $control_settings = new ilSCORM2004Sequencing($this->getId(),true);
1141 
1142  return $control_settings;
1143  }
1144 
1146  include_once ("./Modules/Scorm2004/classes/seq_editor/class.ilSCORM2004Sequencing.php");
1147 
1148  $control_settings = new ilSCORM2004Sequencing($this->getId(),true);
1149  $control_settings->setChoice(ilUtil::yn2tf($_POST["choice"]));
1150  $control_settings->setFlow(ilUtil::yn2tf($_POST["flow"]));
1151  $control_settings->setForwardOnly(ilUtil::yn2tf($_POST["forwardonly"]));
1152  $control_settings->insert();
1153 
1154  return true;
1155  }
1156 
1165  function executeDragDrop($source_id, $target_id, $first_child, $as_subitem = false, $movecopy = "move")
1166  {
1167  $this->slm_tree = new ilTree($this->getId());
1168  $this->slm_tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1169  $this->slm_tree->setTreeTablePK("slm_id");
1170 
1171  require_once("./Modules/Scorm2004/classes/class.ilSCORM2004NodeFactory.php");
1172 
1173  $source_obj = ilSCORM2004NodeFactory::getInstance($this, $source_id, true);
1174  //$source_obj->setLMId($this->getId());
1175 
1176  if (!$first_child)
1177  {
1178  $target_obj = ilSCORM2004NodeFactory::getInstance($this, $target_id, true);
1179  //$target_obj->setLMId($this->getId());
1180  $target_parent = $this->slm_tree->getParentId($target_id);
1181  }
1182 //echo "-".$source_obj->getType()."-";
1183  // handle pages
1184  if ($source_obj->getType() == "page")
1185  {
1186  if ($this->slm_tree->isInTree($source_obj->getId()))
1187  {
1188  $node_data = $this->slm_tree->getNodeData($source_obj->getId());
1189 
1190  // cut on move
1191  if ($movecopy == "move")
1192  {
1193  $parent_id = $this->slm_tree->getParentId($source_obj->getId());
1194  $this->slm_tree->deleteTree($node_data);
1195 
1196  // write history entry
1197 /* require_once("./Services/History/classes/class.ilHistory.php");
1198  ilHistory::_createEntry($source_obj->getId(), "cut",
1199  array(ilLMObject::_lookupTitle($parent_id), $parent_id),
1200  $this->getType().":pg");
1201  ilHistory::_createEntry($parent_id, "cut_page",
1202  array(ilLMObject::_lookupTitle($source_obj->getId()), $source_obj->getId()),
1203  $this->getType().":st");
1204 */
1205  }
1206 /* else // this is not implemented here
1207  {
1208  // copy page
1209  $new_page =& $source_obj->copy();
1210  $source_id = $new_page->getId();
1211  $source_obj =& $new_page;
1212  }
1213 */
1214 
1215  // paste page
1216  if(!$this->slm_tree->isInTree($source_obj->getId()))
1217  {
1218  if ($first_child) // as first child
1219  {
1220  $target_pos = IL_FIRST_NODE;
1221  $parent = $target_id;
1222  }
1223  else if ($as_subitem) // as last child
1224  {
1225  $parent = $target_id;
1226  $target_pos = IL_FIRST_NODE;
1227  $pg_childs = $this->slm_tree->getChildsByType($parent, "page");
1228  if (count($pg_childs) != 0)
1229  {
1230  $target_pos = $pg_childs[count($pg_childs) - 1]["obj_id"];
1231  }
1232  }
1233  else // at position
1234  {
1235  $target_pos = $target_id;
1236  $parent = $target_parent;
1237  }
1238 
1239  // insert page into tree
1240  $this->slm_tree->insertNode($source_obj->getId(),
1241  $parent, $target_pos);
1242 
1243  // write history entry
1244 /* if ($movecopy == "move")
1245  {
1246  // write history comments
1247  include_once("./Services/History/classes/class.ilHistory.php");
1248  ilHistory::_createEntry($source_obj->getId(), "paste",
1249  array(ilLMObject::_lookupTitle($parent), $parent),
1250  $this->getType().":pg");
1251  ilHistory::_createEntry($parent, "paste_page",
1252  array(ilLMObject::_lookupTitle($source_obj->getId()), $source_obj->getId()),
1253  $this->getType().":st");
1254  }
1255 */
1256 
1257  }
1258  }
1259  }
1260 
1261  // handle scos
1262  if ($source_obj->getType() == "sco" || $source_obj->getType() == "ass")
1263  {
1264 //echo "2";
1265  $source_node = $this->slm_tree->getNodeData($source_id);
1266  $subnodes = $this->slm_tree->getSubtree($source_node);
1267 
1268  // check, if target is within subtree
1269  foreach ($subnodes as $subnode)
1270  {
1271  if($subnode["obj_id"] == $target_id)
1272  {
1273  return;
1274  }
1275  }
1276 
1277  $target_pos = $target_id;
1278 
1279  if ($first_child) // as first sco
1280  {
1281  $target_pos = IL_FIRST_NODE;
1282  $target_parent = $target_id;
1283 
1284  $pg_childs = $this->slm_tree->getChildsByType($target_parent, "page");
1285  if (count($pg_childs) != 0)
1286  {
1287  $target_pos = $pg_childs[count($pg_childs) - 1]["obj_id"];
1288  }
1289  }
1290  else if ($as_subitem) // as last sco
1291  {
1292  $target_parent = $target_id;
1293  $target_pos = IL_FIRST_NODE;
1294  $childs = $this->slm_tree->getChilds($target_parent);
1295  if (count($childs) != 0)
1296  {
1297  $target_pos = $childs[count($childs) - 1]["obj_id"];
1298  }
1299  }
1300 
1301  // delete source tree
1302  if ($movecopy == "move")
1303  {
1304  $this->slm_tree->deleteTree($source_node);
1305  }
1306 /* else
1307  {
1308  // copy chapter (incl. subcontents)
1309  $new_chapter =& $source_obj->copy($this->slm_tree, $target_parent, $target_pos);
1310  }
1311 */
1312 
1313  if (!$this->slm_tree->isInTree($source_id))
1314  {
1315  $this->slm_tree->insertNode($source_id, $target_parent, $target_pos);
1316 
1317  // insert moved tree
1318  if ($movecopy == "move")
1319  {
1320  foreach ($subnodes as $node)
1321  {
1322  if($node["obj_id"] != $source_id)
1323  {
1324  $this->slm_tree->insertNode($node["obj_id"], $node["parent"]);
1325  }
1326  }
1327  }
1328  }
1329 
1330  // check the tree
1331 // $this->checkTree();
1332  }
1333 
1334  // handle chapters
1335  if ($source_obj->getType() == "chap")
1336  {
1337 //echo "2";
1338  $source_node = $this->slm_tree->getNodeData($source_id);
1339  $subnodes = $this->slm_tree->getSubtree($source_node);
1340 
1341  // check, if target is within subtree
1342  foreach ($subnodes as $subnode)
1343  {
1344  if($subnode["obj_id"] == $target_id)
1345  {
1346  return;
1347  }
1348  }
1349 
1350  $target_pos = $target_id;
1351 
1352  if ($first_child) // as first chapter
1353  {
1354  $target_pos = IL_FIRST_NODE;
1355  $target_parent = $target_id;
1356 
1357  //$sco_childs = $this->slm_tree->getChildsByType($target_parent, "sco");
1358  //if (count($sco_childs) != 0)
1359  //{
1360  // $target_pos = $sco_childs[count($sco_childs) - 1]["obj_id"];
1361  //}
1362  }
1363  else if ($as_subitem) // as last chapter
1364  {
1365  $target_parent = $target_id;
1366  $target_pos = IL_FIRST_NODE;
1367  $childs = $this->slm_tree->getChilds($target_parent);
1368  if (count($childs) != 0)
1369  {
1370  $target_pos = $childs[count($childs) - 1]["obj_id"];
1371  }
1372  }
1373 
1374  // delete source tree
1375  if ($movecopy == "move")
1376  {
1377  $this->slm_tree->deleteTree($source_node);
1378  }
1379 /* else
1380  {
1381  // copy chapter (incl. subcontents)
1382  $new_chapter =& $source_obj->copy($this->slm_tree, $target_parent, $target_pos);
1383  }
1384 */
1385 
1386  if (!$this->slm_tree->isInTree($source_id))
1387  {
1388  $this->slm_tree->insertNode($source_id, $target_parent, $target_pos);
1389 
1390  // insert moved tree
1391  if ($movecopy == "move")
1392  {
1393  foreach ($subnodes as $node)
1394  {
1395  if($node["obj_id"] != $source_id)
1396  {
1397  $this->slm_tree->insertNode($node["obj_id"], $node["parent"]);
1398  }
1399  }
1400  }
1401  }
1402 
1403  // check the tree
1404 // $this->checkTree();
1405  }
1406 
1407 // $this->checkTree();
1408  }
1409 
1410  function getExportFiles()
1411  {
1412  $file = array();
1413 
1414  require_once("./Modules/Scorm2004/classes/class.ilSCORM2004Export.php");
1415 
1416  $export = new ilSCORM2004Export($this);
1417  foreach ($export->getSupportedExportTypes() as $type)
1418  {
1419  $dir = $export->getExportDirectoryForType($type);
1420  // quit if import dir not available
1421  if (!@is_dir($dir) or !is_writeable($dir))
1422  {
1423  continue;
1424  }
1425  // open directory
1426  $cdir = dir($dir);
1427 
1428  // get files and save the in the array
1429  while ($entry = $cdir->read())
1430  {
1431  if ($entry != "." and
1432  $entry != ".." and
1433  (
1434  ereg("^[0-9]{10}_{2}[0-9]+_{2}(".$this->getType()."_)*[0-9]+\.zip\$", $entry) or
1435  ereg("^[0-9]{10}_{2}[0-9]+_{2}(".$this->getType()."_)*[0-9]+\.pdf\$", $entry) or
1436  ereg("^[0-9]{10}_{2}[0-9]+_{2}(".$this->getType()."_)*[0-9]+\.iso\$", $entry)
1437  ))
1438  {
1439  $file[$entry.$type] = array("type" => $type, "file" => $entry,
1440  "size" => filesize($dir."/".$entry));
1441  }
1442  }
1443 
1444  // close import directory
1445  $cdir->close();
1446  }
1447 
1448  // sort files
1449  ksort ($file);
1450  reset ($file);
1451  return $file;
1452  }
1453 
1457  function exportScorm($a_inst, $a_target_dir, $ver, &$expLog)
1458  {
1459 
1460  $a_xml_writer = new ilXmlWriter;
1461 
1462  // export metadata
1463  $this->exportXMLMetaData($a_xml_writer);
1464  $metadata_xml = $a_xml_writer->xmlDumpMem(false);
1465  $a_xml_writer->_XmlWriter;
1466 
1467  $xsl = file_get_contents("./Modules/Scorm2004/templates/xsl/metadata.xsl");
1468  $args = array( '/_xml' => $metadata_xml , '/_xsl' => $xsl );
1469  $xh = xslt_create();
1470  $output = xslt_process($xh,"arg:/_xml","arg:/_xsl",NULL,$args,NULL);
1471  xslt_free($xh);
1472  file_put_contents($a_target_dir.'/indexMD.xml',$output);
1473 
1474  // export glossary
1475  if($this->getAssignedGlossary()!=0)
1476  {
1477  ilUtil::makeDir($a_target_dir."/glossary");
1478  include_once("./Modules/Glossary/classes/class.ilObjGlossary.php");
1479  include_once("./Modules/Glossary/classes/class.ilGlossaryExport.php");
1480  $glo_xml_writer = new ilXmlWriter();
1481 
1482  $glo_xml_writer->xmlSetDtdDef("<!DOCTYPE ContentObject SYSTEM \"http://www.ilias.de/download/dtd/ilias_co_3_7.dtd\">");
1483  // set xml header
1484  $glo_xml_writer->xmlHeader();
1485  $glos = new ilObjGlossary($this->getAssignedGlossary(), false);
1486  //$glos->exportHTML($a_target_dir."/glossary", $expLog);
1487  $glos_export = new ilGlossaryExport($glos,"xml");
1488  $glos->exportXML($glo_xml_writer,$glos_export->getInstId(), $a_target_dir."/glossary", $expLog);
1489  $glo_xml_writer->xmlDumpFile($a_target_dir."/glossary/glossary.xml");
1490  $glo_xml_writer->_XmlWriter;
1491  }
1492 
1493  $a_xml_writer = new ilXmlWriter;
1494  // set dtd definition
1495  $a_xml_writer->xmlSetDtdDef("<!DOCTYPE ContentObject SYSTEM \"http://www.ilias.de/download/dtd/ilias_co_3_7.dtd\">");
1496 
1497  // set generated comment
1498  $a_xml_writer->xmlSetGenCmt("Export of ILIAS Content Module ". $this->getId()." of installation ".$a_inst.".");
1499 
1500  // set xml header
1501  $a_xml_writer->xmlHeader();
1502 
1503  global $ilBench;
1504 
1505  $a_xml_writer->xmlStartTag("ContentObject", array("Type"=>"SCORM2004LearningModule"));
1506 
1507  // MetaData
1508  $this->exportXMLMetaData($a_xml_writer);
1509 
1510  $this->exportXMLStructureObjects($a_xml_writer, $a_inst, $expLog);
1511 
1512  // SCO Objects
1513  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Sco Objects");
1514  $this->exportXMLScoObjects($a_inst, $a_target_dir, $ver, $expLog);
1515  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Sco Objects");
1516 
1517  $a_xml_writer->xmlEndTag("ContentObject");
1518  $a_xml_writer->xmlDumpFile($a_target_dir.'/index.xml', false);
1519 
1520  if ($ver == "2004 4th") {
1521  $revision ="4th";
1522  $ver = "2004";
1523  }
1524 
1525  if ($ver == "2004 3rd") {
1526  $revision ="3rd";
1527  $ver = "2004";
1528  }
1529 
1530  // add content css (note: this is also done per item)
1531  $css_dir = $a_target_dir."/ilias_css_4_2";
1532  ilUtil::makeDir($css_dir);
1533  include_once("./Modules/Scorm2004/classes/class.ilScormExportUtil.php");
1534  ilScormExportUtil::exportContentCSS($this, $css_dir);
1535 
1536  // add manifest
1537  include_once("./Modules/Scorm2004/classes/class.ilContObjectManifestBuilder.php");
1538  $manifestBuilder = new ilContObjectManifestBuilder($this);
1539  $manifestBuilder->buildManifest($ver,$revision);
1540  $manifestBuilder->dump($a_target_dir);
1541 
1542  $xsl = file_get_contents("./Modules/Scorm2004/templates/xsl/module.xsl");
1543  $args = array( '/_xml' => file_get_contents($a_target_dir."/imsmanifest.xml"), '/_xsl' => $xsl );
1544  $xh = xslt_create();
1545  $output = xslt_process($xh,"arg:/_xml","arg:/_xsl",NULL,$args,NULL);
1546  xslt_free($xh);
1547  fputs(fopen($a_target_dir.'/index.html','w+'),$output);
1548  // copy xsd files to target
1549  switch ($ver)
1550  {
1551  case "2004":
1552  if ($revision == "3rd") {
1553  ilUtil::rCopy('./Modules/Scorm2004/templates/xsd/adlcp_130_export_2004',$a_target_dir,false);
1554  }
1555 
1556  if ($revision == "4th") {
1557  ilUtil::rCopy('./Modules/Scorm2004/templates/xsd/adlcp_130_export_2004_4th',$a_target_dir,false);
1558  }
1559  break;
1560  case "12":
1561  ilUtil::rCopy('./Modules/Scorm2004/templates/xsd/adlcp_120_export_12',$a_target_dir,false);
1562  break;
1563  }
1564 
1565  $a_xml_writer->_XmlWriter;
1566  }
1567 
1568 
1569  function exportHTML4PDF($a_inst, $a_target_dir, &$expLog)
1570  {
1571  global $ilBench;
1572  $tree = new ilTree($this->getId());
1573  $tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1574  $tree->setTreeTablePK("slm_id");
1575  foreach($tree->getSubTree($tree->getNodeData($tree->getRootId()),true,'sco') as $sco)
1576  {
1577  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Sco.php");
1578  $sco_folder = $a_target_dir."/".$sco['obj_id'];
1579  ilUtil::makeDir($sco_folder);
1580  $node = new ilSCORM2004Sco($this,$sco['obj_id']);
1581  $node->exportHTML4PDF($a_inst, $sco_folder, $expLog);
1582  }
1583  }
1584 
1585  function exportPDF($a_inst, $a_target_dir, &$expLog)
1586  {
1587  global $ilBench;
1588  $a_xml_writer = new ilXmlWriter;
1589  $a_xml_writer->xmlStartTag("ContentObject", array("Type"=>"SCORM2004SCO"));
1590  $this->exportXMLMetaData($a_xml_writer);
1591  $tree = new ilTree($this->getId());
1592  $tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1593  $tree->setTreeTablePK("slm_id");
1594  foreach($tree->getSubTree($tree->getNodeData($tree->getRootId()),true,'sco') as $sco)
1595  {
1596  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Sco.php");
1597  $sco_folder = $a_target_dir."/".$sco['obj_id'];
1598  ilUtil::makeDir($sco_folder);
1599  $node = new ilSCORM2004Sco($this,$sco['obj_id']);
1600  $node->exportPDFPrepareXmlNFiles($a_inst, $a_target_dir, $expLog, $a_xml_writer);
1601  }
1602  if($this->getAssignedGlossary()!=0)
1603  {
1604  ilUtil::makeDir($a_target_dir."/glossary");
1605  include_once("./Modules/Glossary/classes/class.ilObjGlossary.php");
1606  include_once("./Modules/Glossary/classes/class.ilGlossaryExport.php");
1607  $glos = new ilObjGlossary($this->getAssignedGlossary(), false);
1608  $glos_export = new ilGlossaryExport($glos,"xml");
1609  $glos->exportXML($a_xml_writer,$glos_export->getInstId(), $a_target_dir."/glossary", $expLog);
1610  }
1611  copy('./templates/default/images/icon_attachment_s.png',$a_target_dir."/icon_attachment_s.png");
1612  $a_xml_writer->xmlEndTag("ContentObject");
1613  include_once 'Services/Transformation/classes/class.ilXML2FO.php';
1614  $xml2FO = new ilXML2FO();
1615  $xml2FO->setXSLTLocation('./Modules/Scorm2004/templates/xsl/contentobject2fo.xsl');
1616  $xml2FO->setXMLString($a_xml_writer->xmlDumpMem());
1617  $xml2FO->setXSLTParams(array ('target_dir' => $a_target_dir));
1618  $xml2FO->transform();
1619  $fo_string = $xml2FO->getFOString();
1620  $fo_xml = simplexml_load_string($fo_string);
1621  $fo_ext = $fo_xml->xpath("//fo:declarations");
1622  $fo_ext = $fo_ext[0];
1623  $results = array();
1624  include_once "./Services/Utilities/classes/class.ilFileUtils.php";
1625  ilFileUtils::recursive_dirscan($a_target_dir."/objects", $results);
1626  if (is_array($results["file"]))
1627  {
1628  foreach ($results["file"] as $key => $value)
1629  {
1630  $e = $fo_ext->addChild("fox:embedded-file","","http://xml.apache.org/fop/extensions");
1631  $e->addAttribute("src",$results[path][$key].$value);
1632  $e->addAttribute("name",$value);
1633  $e->addAttribute("desc","");
1634  }
1635  }
1636  $fo_string = $fo_xml->asXML();
1637  $a_xml_writer->_XmlWriter;
1638  return $fo_string;
1639  }
1640 
1641  function exportHTMLOne($a_inst, $a_target_dir, &$expLog)
1642  {
1643  $one_file = fopen($a_target_dir.'/index.html','w+');
1644  $this->exportHTML($a_inst, $a_target_dir, $expLog, $one_file);
1645  fclose($one_file);
1646  }
1647 
1651  function exportHTML($a_inst, $a_target_dir, &$expLog, $a_one_file = "")
1652  {
1653 
1654 // $a_xml_writer = new ilXmlWriter;
1655  // set dtd definition
1656 // $a_xml_writer->xmlSetDtdDef("<!DOCTYPE ContentObject SYSTEM \"http://www.ilias.de/download/dtd/ilias_co_3_7.dtd\">");
1657 
1658  // set generated comment
1659 // $a_xml_writer->xmlSetGenCmt("Export of ILIAS Content Module ". $this->getId()." of installation ".$a_inst.".");
1660 
1661  // set xml header
1662 // $a_xml_writer->xmlHeader();
1663 
1664 // global $ilBench;
1665 
1666 // $a_xml_writer->xmlStartTag("ContentObject", array("Type"=>"SCORM2004LearningModule"));
1667 
1668 // $expLog->write(date("[y-m-d H:i:s] ")."Start Export Sco Objects");
1669  $this->exportHTMLScoObjects($a_inst, $a_target_dir, $expLog, $a_one_file);
1670 // $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Sco Objects");
1671 
1672 // $a_xml_writer->xmlEndTag("ContentObject");
1673 
1674 
1675  /*$toc_tpl = new ilTemplate("tpl.main.html", true, true, false);
1676  $style_name = $ilUser->prefs["style"].".css";
1677  $tpl->setCurrentBlock("css_file");
1678  $tpl->setVariable("CSS_FILE", $style_name);
1679  $tpl->parseCurrentBlock();*/
1680 
1681  if ($a_one_file == "")
1682  {
1683  include_once("./Modules/Scorm2004/classes/class.ilContObjectManifestBuilder.php");
1684  $manifestBuilder = new ilContObjectManifestBuilder($this);
1685  $manifestBuilder->buildManifest('12');
1686 
1687  include_once("Services/Frameset/classes/class.ilFramesetGUI.php");
1688  $fs_gui = new ilFramesetGUI();
1689  $fs_gui->setFramesetTitle($this->getTitle());
1690  $fs_gui->setMainFrameSource("");
1691  $fs_gui->setSideFrameSource("toc.html");
1692  $fs_gui->setMainFrameName("content");
1693  $fs_gui->setSideFrameName("toc");
1694  $output = $fs_gui->get();
1695  fputs(fopen($a_target_dir.'/index.html','w+'),$output);
1696 
1697  $xsl = file_get_contents("./Modules/Scorm2004/templates/xsl/module.xsl");
1698  $xml = simplexml_load_string($manifestBuilder->writer->xmlDumpMem());
1699  $args = array( '/_xml' => $xml->organizations->organization->asXml(), '/_xsl' => $xsl );
1700  $xh = xslt_create();
1701  $output = xslt_process($xh,"arg:/_xml","arg:/_xsl",NULL,$args,NULL);
1702  xslt_free($xh);
1703  fputs(fopen($a_target_dir.'/toc.html','w+'),$output);
1704  }
1705 // $a_xml_writer->_XmlWriter;
1706  }
1707 
1714  function exportXMLMetaData(&$a_xml_writer)
1715  {
1716  include_once("Services/MetaData/classes/class.ilMD2XML.php");
1717  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
1718  $md2xml->setExportMode(true);
1719  $md2xml->startExport();
1720  $a_xml_writer->appendXML($md2xml->getXML());
1721  }
1722 
1729  function exportXMLStructureObjects(&$a_xml_writer, $a_inst, &$expLog)
1730  {
1731  include_once("Services/MetaData/classes/class.ilMD2XML.php");
1732  $tree = new ilTree($this->getId());
1733  $tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1734  $tree->setTreeTablePK("slm_id");
1735  $a_xml_writer->xmlStartTag("StructureObject");
1736  foreach($tree->getFilteredSubTree($tree->getRootId(),Array('page')) as $obj)
1737  {
1738  if($obj['type']=='') continue;
1739 
1740  //$md2xml = new ilMD2XML($obj['obj_id'], 0, $obj['type']);
1741  $md2xml = new ilMD2XML($this->getId(), $obj['obj_id'], $obj['type']);
1742  $md2xml->setExportMode(true);
1743  $md2xml->startExport();
1744  $a_xml_writer->appendXML($md2xml->getXML());
1745  }
1746  $a_xml_writer->xmlEndTag("StructureObject");
1747  }
1748 
1749 
1756  function exportXMLScoObjects($a_inst, $a_target_dir, $ver, &$expLog)
1757  {
1758  global $ilBench;
1759  $tree = new ilTree($this->getId());
1760  $tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1761  $tree->setTreeTablePK("slm_id");
1762  foreach($tree->getSubTree($tree->getNodeData($tree->getRootId()),true,array('sco','ass')) as $sco)
1763  {
1764  if ($sco['type'] == "sco")
1765  {
1766  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Sco.php");
1767  $sco_folder = $a_target_dir."/".$sco['obj_id'];
1768  ilUtil::makeDir($sco_folder);
1769  $node = new ilSCORM2004Sco($this,$sco['obj_id']);
1770  $node->exportScorm($a_inst, $sco_folder, $ver, $expLog);
1771  }
1772  if ($sco['type'] == "ass")
1773  {
1774  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Asset.php");
1775  $sco_folder = $a_target_dir."/".$sco['obj_id'];
1776  ilUtil::makeDir($sco_folder);
1777  $node = new ilSCORM2004Asset($this,$sco['obj_id']);
1778  $node->exportScorm($a_inst, $sco_folder, $ver, $expLog);
1779  }
1780 
1781  }
1782  }
1783 
1784  /* export page objects to xml (see ilias_co.dtd)
1785  *
1786  * @param object $a_xml_writer ilXmlWriter object that receives the
1787  * xml data
1788  */
1789  function exportHTMLScoObjects($a_inst, $a_target_dir, &$expLog, $a_one_file = "")
1790  {
1791  global $ilBench;
1792 
1793  $tree = new ilTree($this->getId());
1794  $tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
1795  $tree->setTreeTablePK("slm_id");
1796 
1797  // copy all necessary files now
1798  if ($a_one_file != "")
1799  {
1800  $this->prepareHTMLExporter($a_target_dir);
1801 
1802  // put header into file
1803  $sco_tpl = new ilTemplate("tpl.sco.html", true, true, "Modules/Scorm2004");
1804  include_once("./Services/COPage/classes/class.ilCOPageHTMLExport.php");
1805  $sco_tpl = ilCOPageHTMLExport::getPreparedMainTemplate($sco_tpl);
1806 
1807  $sco_tpl->setCurrentBlock("js_file");
1808  $sco_tpl->setVariable("JS_FILE", "./js/pure.js");
1809  $sco_tpl->parseCurrentBlock();
1810  $sco_tpl->setCurrentBlock("js_file");
1811  $sco_tpl->setVariable("JS_FILE", "./js/question_handling.js");
1812  $sco_tpl->parseCurrentBlock();
1813 
1814 
1815  $sco_tpl->setCurrentBlock("head");
1816  $sco_tpl->parseCurrentBlock();
1817  fputs($a_one_file, $sco_tpl->get("head"));
1818 
1819  // toc
1820  include_once("./Modules/Scorm2004/classes/class.ilContObjectManifestBuilder.php");
1821  $manifestBuilder = new ilContObjectManifestBuilder($this);
1822  $manifestBuilder->buildManifest('12');
1823  $xsl = file_get_contents("./Modules/Scorm2004/templates/xsl/module.xsl");
1824  $xml = simplexml_load_string($manifestBuilder->writer->xmlDumpMem());
1825  $args = array( '/_xml' => $xml->organizations->organization->asXml(), '/_xsl' => $xsl );
1826  $xh = xslt_create();
1827  $params = array("one_page" => "y");
1828  $output = xslt_process($xh,"arg:/_xml","arg:/_xsl",NULL,$args,$params);
1829  xslt_free($xh);
1830  fputs($a_one_file, $output);
1831 
1832  }
1833 
1834  foreach($tree->getSubTree($tree->getNodeData($tree->getRootId()),true,'sco') as $sco)
1835  {
1836  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Sco.php");
1837  $sco_folder = $a_target_dir."/".$sco['obj_id'];
1838  ilUtil::makeDir($sco_folder);
1839  $node = new ilSCORM2004Sco($this,$sco['obj_id']);
1840 
1841  if ($a_one_file == "")
1842  {
1843  $node->exportHTML($a_inst, $sco_folder, $expLog, $a_one_file);
1844  }
1845  else
1846  {
1847  $node->exportHTMLPageObjects($a_inst, $a_target_dir, $expLog, 'full',
1848  "sco", $a_one_file, $sco_tpl);
1849  }
1850  if($this->getAssignedGlossary()!=0)
1851  {
1852  include_once("./Modules/Glossary/classes/class.ilObjGlossary.php");
1853  $glos = new ilObjGlossary($this->getAssignedGlossary(),false);
1854  //$glos->exportHTML($sco_folder."/glossary", $expLog);
1855  }
1856  }
1857 
1858  // copy all necessary files now
1859  if ($a_one_file != "")
1860  {
1861  // put tail into file
1862  fputs($a_one_file, $sco_tpl->get("tail"));
1863  }
1864 
1865  }
1866 
1873  function prepareHTMLExporter($a_target_dir)
1874  {
1875  // system style html exporter
1876  include_once("./Services/Style/classes/class.ilSystemStyleHTMLExport.php");
1877  $this->sys_style_html_export = new ilSystemStyleHTMLExport($a_target_dir);
1878  $this->sys_style_html_export->export();
1879 
1880  // init co page html exporter
1881  include_once("./Services/COPage/classes/class.ilCOPageHTMLExport.php");
1882  $this->co_page_html_export = new ilCOPageHTMLExport($a_target_dir);
1883  $this->co_page_html_export->setContentStyleId(
1884  $this->getStyleSheetId());
1885  $this->co_page_html_export->createDirectories();
1886  $this->co_page_html_export->exportStyles();
1887  $this->co_page_html_export->exportSupportScripts();
1888 
1889  include_once("./Services/MediaObjects/classes/class.ilPlayerUtil.php");
1890  $this->flv_dir = $a_target_dir."/".ilPlayerUtil::getFlashVideoPlayerDirectory();
1891 
1892  ilUtil::makeDir($a_target_dir.'/css/yahoo');
1893  ilUtil::makeDir($a_target_dir.'/objects');
1894  ilUtil::makeDir($a_target_dir.'/players');
1895  ilUtil::makeDir($this->flv_dir);
1896 
1897  include_once("./Services/MediaObjects/classes/class.ilPlayerUtil.php");
1898 // copy(ilPlayerUtil::getFlashVideoPlayerFilename(true),
1899 // $a_target_dir.'/js/'.ilPlayerUtil::getFlashVideoPlayerFilename());
1901 
1902  copy('./Services/MediaObjects/flash_mp3_player/mp3player.swf', $a_target_dir.'/players/mp3player.swf');
1903  copy('./Modules/Scorm2004/scripts/scorm_2004.js',$a_target_dir.'/js/scorm.js');
1904  copy('./Modules/Scorm2004/scripts/pager.js',$a_target_dir.'/js/pager.js');
1905  copy('./Modules/Scorm2004/scripts/questions/pure.js',$a_target_dir.'/js/pure.js');
1906  copy('./Modules/Scorm2004/scripts/questions/question_handling.js',
1907  $a_target_dir.'/js/question_handling.js');
1908 
1909  }
1910 
1918  function getPublicExportFile($a_type)
1919  {
1920  return $this->public_export_file[$a_type];
1921  }
1922 
1927  function exportFileItems($a_target_dir, &$expLog)
1928  {
1929  include_once("./Modules/File/classes/class.ilObjFile.php");
1930 
1931  foreach ($this->file_ids as $file_id)
1932  {
1933  $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
1934  $file_obj = new ilObjFile($file_id, false);
1935  $file_obj->export($a_target_dir);
1936  unset($file_obj);
1937  }
1938  }
1939 
1943  function setPublicExportFile($a_type, $a_file)
1944  {
1945  $this->public_export_file[$a_type] = $a_file;
1946  }
1947 
1958  public static function _getMaxScoreForUser($a_id, $a_user)
1959  {
1960  global $ilDB;
1961 
1962  $scos = array();
1963 
1964  $result = $ilDB->query(
1965  'SELECT cp_node.cp_node_id '
1966  .'FROM cp_node, cp_resource, cp_item '
1967  .'WHERE cp_item.cp_node_id = cp_node.cp_node_id '
1968  .'AND cp_item.resourceId = cp_resource.id '
1969  .'AND scormType = '.$ilDB->quote('sco', 'text').' '
1970  .'AND nodeName = '.$ilDB->quote('item', 'text').' '
1971  .'AND cp_node.slm_id = '.$ilDB->quote($a_id, 'integer').' '
1972  .'GROUP BY cp_node.cp_node_id'
1973  );
1974 
1975  while($row = $ilDB->fetchAssoc($result))
1976  {
1977  array_push($scos, $row['cp_node_id']);
1978  }
1979 
1980  $set = 0; //numbers of SCO that set cmi.score.scaled
1981  $max = null;
1982  for($i = 0; $i < count($scos); $i++)
1983  {
1984  $res = $ilDB->queryF(
1985  'SELECT c_max FROM cmi_node WHERE (user_id = %s AND cp_node_id = %s)',
1986  array('integer', 'integer'),
1987  array($a_user, $scos[$i])
1988  );
1989 
1990  if($ilDB->numRows($res) > 0)
1991  {
1992  $row = $ilDB->fetchAssoc($res);
1993  if($row['c_max'] != null)
1994  {
1995  $set++;
1996  $max = $row['c_max'];
1997  }
1998  }
1999  }
2000  $retVal = ($set == 1) ? $max : null;
2001 
2002  return $retVal;
2003  }
2004 
2005  public static function _getScores2004ForUser($a_cp_node_id, $a_user) {
2006  global $ilDB;
2007  $retAr = array("raw" => null, "max" => null, "scaled" => null);
2008  $val_set = $ilDB->queryF("SELECT c_raw, c_max, scaled FROM cmi_node WHERE (user_id = %s AND cp_node_id = %s)",
2009  array('integer', 'integer'),
2010  array($a_user, $a_cp_node_id)
2011  );
2012  if ($val_set->numRows()>0)
2013  {
2014  $val_rec = $ilDB->fetchAssoc($val_set);
2015  $retAr["raw"] = $val_rec['c_raw'];
2016  $retAr["max"] = $val_rec['c_max'];
2017  $retAr["scaled"] = $val_rec['scaled'];
2018  if ($val_rec['scaled']==null && $val_rec['c_raw']!=null && $val_rec['c_max']!=null) {
2019  $retAr["scaled"] = ($val_rec['c_raw'] / $val_rec['c_max']);
2020  }
2021  }
2022  return $retAr;
2023  }
2024 
2031  function copyAuthoredContent($a_new_obj)
2032  {
2033  global $ilias;
2034 
2035  // set/copy stylesheet
2036  include_once("./Services/Style/classes/class.ilObjStyleSheet.php");
2037  $style_id = $this->getStyleSheetId();
2038  if ($style_id > 0 && !ilObjStyleSheet::_lookupStandard($style_id))
2039  {
2040  $style_obj = $ilias->obj_factory->getInstanceByObjId($style_id);
2041  $new_id = $style_obj->ilClone();
2042  $a_new_obj->setStyleSheetId($new_id);
2043  $a_new_obj->update();
2044  }
2045 
2046  $a_new_obj->createScorm2004Tree();
2047  $source_tree = $this->getTree();
2048  $target_tree_root_id = $a_new_obj->getTree()->readRootId();
2049  $childs = $source_tree->getChilds($source_tree->readRootId());
2050  $a_copied_nodes = array();
2051  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004Node.php");
2052  foreach ($childs as $c)
2053  {
2054  ilSCORM2004Node::pasteTree($a_new_obj, $c["child"], $target_tree_root_id,
2055  IL_LAST_NODE, "", $a_copied_nodes, true, false);
2056  }
2057  }
2058 
2059 }
2060 ?>